{"templateId":"markdown","sharedDataIds":{"sidebar":"sidebar-sidebars.yaml"},"props":{"metadata":{"markdoc":{"tagList":["admonition"]},"redocly_category":"Products","product_name":"Engage Studio","type":"markdown"},"seo":{"title":"iOS Developer Guide","description":"Comprehensive iOS developer guide for integrating Engage Studio Mobile Push notifications, covering APNs token management, rich notifications, and event tracking for mobile apps.","siteUrl":"https://docs.treasure.ai","lang":"en-US","jsonLd":{"@context":"https://schema.org","@graph":[{"@type":"Organization","@id":"https://www.treasure.ai/","name":"Treasure AI","url":"https://www.treasure.ai/","logo":"https://www.treasure.ai/hubfs/assets/images/logos/primary-logo.svg"},{"@type":"WebSite","@id":"https://docs.treasure.ai/#website","name":"Treasure AI Documentation","url":"https://docs.treasure.ai/","inLanguage":["en","ja"],"publisher":{"@id":"https://www.treasure.ai/"}}]},"llmstxt":{"hide":false,"sections":[{"title":"Table of contents","includeFiles":["**/*"],"excludeFiles":[]}],"excludeFiles":[]}},"dynamicMarkdocComponents":[],"compilationErrors":[],"ast":{"$$mdtype":"Tag","name":"article","attributes":{},"children":[{"$$mdtype":"Tag","name":"Heading","attributes":{"level":1,"id":"ios-developer-guide","__idx":0},"children":["iOS Developer Guide"]},{"$$mdtype":"Tag","name":"Admonition","attributes":{"type":"warning","name":"Beta Feature"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Mobile Push is currently in beta. Features, APIs, and implementation details may change before general availability."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"overview","__idx":1},"children":["Overview"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["This guide provides implementation requirements for integrating Engage Studio Mobile Push notifications in your iOS app using the Treasure Data iOS SDK. Your development team must implement the following functionality:"]},{"$$mdtype":"Tag","name":"ol","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["APNs/FCM Integration"]},": Receive push notifications via Apple Push Notification Service and Firebase Cloud Messaging"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Token Management"]},": Register and update device tokens with Treasure Data"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Rich Notifications"]},": Display notifications with images using Notification Service Extension"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Event Tracking"]},": Track user interactions (delivery, open, dismiss, links) using Treasure Data SDK"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Automated Data Upload"]},": Treasure Data SDK automatically handles event upload to Treasure Data"]}]},{"$$mdtype":"Tag","name":"Admonition","attributes":{"type":"info","name":"Sample Implementation Available"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["A complete, production-ready sample application is available on GitHub:"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"https://github.com/treasure-data/engage-push-notification-sample/tree/main/ios"},"children":["Treasure Data Mobile Push - iOS Sample"]}]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The sample includes:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Complete AppDelegate implementation with FCM and Treasure Data SDK integration"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Notification Service Extension for rich media"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Event tracking with Treasure Data SDK"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Deep link and web link handling"]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Clone the repository and use it as a reference for your implementation."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"requirements","__idx":2},"children":["Requirements"]},{"$$mdtype":"Tag","name":"div","attributes":{"className":"md-table-wrapper"},"children":[{"$$mdtype":"Tag","name":"table","attributes":{"className":"md"},"children":[{"$$mdtype":"Tag","name":"thead","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Component"},"children":["Component"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Requirement"},"children":["Requirement"]}]}]},{"$$mdtype":"Tag","name":"tbody","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Minimum iOS Version"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["iOS 15.0 or later"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Language"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Swift (recommended) or Objective-C"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Required Frameworks"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Firebase Messaging SDK 12.7.0+"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Treasure Data iOS SDK 1.2.1+"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["UserNotifications framework"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["SafariServices (for web link handling)"]}]}]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Xcode Version"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Xcode 14.0 or later"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Tracked Events"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["delivery"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["open"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["dismiss"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["deeplink_open"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["link_open"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["token_register"]}]}]}]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"architecture-overview","__idx":3},"children":["Architecture Overview"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Your iOS app implementation consists of the following components:"]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"1-appdelegate-configuration","__idx":4},"children":["1. AppDelegate Configuration"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Purpose:"]}," Initialize Firebase, Treasure Data SDK, and configure notification delegates"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Key Responsibilities:"]}]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Initialize Firebase SDK"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Initialize Treasure Data SDK with endpoint and database configuration"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Set notification center delegates"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Request notification permissions from user"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Register for remote notifications"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Handle notification events in foreground and background"]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Reference:"]}," See ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["AppDelegate.swift"]}," in the ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"https://github.com/treasure-data/engage-push-notification-sample/tree/main/ios"},"children":["sample repository"]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"2-notification-service-extension","__idx":5},"children":["2. Notification Service Extension"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Purpose:"]}," Download and attach images to notifications"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Key Responsibilities:"]}]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Receive notification before display"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Extract ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["image_url"]}," from payload"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Download image from remote URL"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Create UNNotificationAttachment"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Add attachment to notification content"]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Reference:"]}," See ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["NotificationService.swift"]}," in the ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"https://github.com/treasure-data/engage-push-notification-sample/tree/main/ios"},"children":["sample repository"]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"3-tracking-service","__idx":6},"children":["3. Tracking Service"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Purpose:"]}," Manage event tracking with Treasure Data SDK"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Key Responsibilities:"]}]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Track all push notification events using Treasure Data SDK"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Handle ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["delivery"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["open"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["dismiss"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["link_open"]},", and ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["deeplink_open"]}," events"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Associate events with FCM token and user ID"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Manage event data formatting"]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Reference:"]}," See ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["TrackingService.swift"]}," in the ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"https://github.com/treasure-data/engage-push-notification-sample/tree/main/ios"},"children":["sample repository"]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"4-deep-link-handler","__idx":7},"children":["4. Deep Link Handler"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Purpose:"]}," Handle deep links from notifications"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Key Responsibilities:"]}]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Receive deep link URLs via SceneDelegate or AppDelegate"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Parse URL scheme and path"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Navigate to appropriate screen based on deep link"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Open web URLs in Safari"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Track deep link events"]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Reference:"]}," See ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["SceneDelegate.swift"]}," in the ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"https://github.com/treasure-data/engage-push-notification-sample/tree/main/ios"},"children":["sample repository"]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"project-setup","__idx":8},"children":["Project Setup"]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"step-1-generate-xcode-project-with-xcodegen","__idx":9},"children":["Step 1: Generate Xcode Project with XcodeGen"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The sample app uses XcodeGen to generate the Xcode project. Install XcodeGen:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"bash","header":{"controls":{"copy":{}}},"source":"brew install xcodegen\n","lang":"bash"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Generate the Xcode project:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"bash","header":{"controls":{"copy":{}}},"source":"cd ios\nxcodegen generate\n","lang":"bash"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"step-2-add-firebase-and-treasure-data-sdk","__idx":10},"children":["Step 2: Add Firebase and Treasure Data SDK"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The project uses Swift Package Manager for dependency management. Dependencies are defined in ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["project.yml"]},":"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Firebase iOS SDK"]}," (12.7.0+):"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["FirebaseMessaging"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["FirebaseAnalytics"]}]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Treasure Data iOS SDK"]}," (1.2.1+):"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Complete SDK for event tracking and data upload"]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Dependencies are automatically resolved when you open the generated Xcode project."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"step-3-configure-firebase","__idx":11},"children":["Step 3: Configure Firebase"]},{"$$mdtype":"Tag","name":"ol","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Download ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["GoogleService-Info.plist"]}," from Firebase Console"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Copy the file to your project:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"bash","header":{"controls":{"copy":{}}},"source":"cp GoogleService-Info.plist ios/TDPushSample/GoogleService-Info.plist\n","lang":"bash"},"children":[]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Ensure the file is added to your main app target in Xcode"]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"step-4-configure-treasure-data-in-infoplist","__idx":12},"children":["Step 4: Configure Treasure Data in Info.plist"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Add your Treasure Data configuration to ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Info.plist"]},":"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"xml","header":{"controls":{"copy":{}}},"source":"<key>TDWriteKey</key>\n<string>your_write_api_key_here</string>\n<key>TDDatabase</key>\n<string>mobile</string>\n<key>TDTable</key>\n<string>push_events</string>\n<key>TDEndpoint</key>\n<string>https://in.treasuredata.com</string>\n","lang":"xml"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Important:"]}," Do not commit your actual API key to version control. Use placeholder values and document the required configuration."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"step-5-configure-capabilities-in-xcode","__idx":13},"children":["Step 5: Configure Capabilities in Xcode"]},{"$$mdtype":"Tag","name":"ol","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Select your project in Project Navigator"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Select your app target"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Go to ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Signing & Capabilities"]}," tab"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Click ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["+ Capability"]}," and add:",{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Push Notifications"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Background Modes"]}," → Check ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Remote notifications"]}]}]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"step-6-create-notification-service-extension-for-rich-media","__idx":14},"children":["Step 6: Create Notification Service Extension (for Rich Media)"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["To support images in notifications, you need a Notification Service Extension:"]},{"$$mdtype":"Tag","name":"ol","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["In Xcode, go to ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["File"]}," > ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["New"]}," > ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Target"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Select ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Notification Service Extension"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Enter extension name (e.g., ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["NotificationService"]},")"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Click ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Finish"]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"step-7-configure-infoplist-for-deep-links","__idx":15},"children":["Step 7: Configure Info.plist for Deep Links"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Add URL scheme support to ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Info.plist"]},":"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"xml","header":{"controls":{"copy":{}}},"source":"<key>CFBundleURLTypes</key>\n<array>\n    <dict>\n        <key>CFBundleURLSchemes</key>\n        <array>\n            <string>myapp</string>\n        </array>\n        <key>CFBundleURLName</key>\n        <string>com.example.myapp</string>\n    </dict>\n</array>\n","lang":"xml"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"data-payload-schema","__idx":16},"children":["Data Payload Schema"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Your app will receive the following JSON structure in the notification ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["userInfo"]},". In addition to your custom data fields, Engage Studio includes the standard APNs ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["aps"]}," dictionary with the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["content-available"]}," and ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["category"]}," fields that enable delivery and dismiss tracking (see ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"#apns-fields-for-delivery-and-dismiss-tracking"},"children":["APNs fields for delivery and dismiss tracking"]}," below):"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"json","header":{"controls":{"copy":{}}},"source":"{\n  \"aps\": {\n    \"alert\": {\n      \"title\": \"Special Offer!\",\n      \"body\": \"Get 20% off your next purchase\"\n    },\n    \"content-available\": 1,\n    \"category\": \"default\"\n  },\n  \"td_campaign_id\": \"cmp_20251214_promo\",\n  \"title\": \"Special Offer!\",\n  \"body\": \"Get 20% off your next purchase\",\n  \"image_url\": \"https://cdn.example.com/banner.png\",\n  \"link\": \"https://example.com/promo\"\n}\n","lang":"json"},"children":[]},{"$$mdtype":"Tag","name":"div","attributes":{"className":"md-table-wrapper"},"children":[{"$$mdtype":"Tag","name":"table","attributes":{"className":"md"},"children":[{"$$mdtype":"Tag","name":"thead","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Field"},"children":["Field"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Type"},"children":["Type"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Required"},"children":["Required"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Description"},"children":["Description"]}]}]},{"$$mdtype":"Tag","name":"tbody","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["aps.content-available"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Integer"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Yes"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Set to ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["1"]}," by Engage Studio. Tells iOS to wake your app briefly in the background when the notification is received, so your app can record a ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["delivery"]}," event even when it is not in the foreground."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["aps.category"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["String"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Yes"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Set to ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["default"]}," by Engage Studio. Identifies the notification category your app registers so it can receive a callback when the user dismisses the notification, enabling ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["dismiss"]}," tracking."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["td_campaign_id"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["String"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Yes"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Unique campaign identifier from Engage Studio"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["title"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["String"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Yes"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Notification title"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["body"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["String"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Yes"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Notification body text"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["image_url"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["String"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["No"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["URL for rich notification image"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["link"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["String"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["No"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Web URL to open in Safari"]}]}]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"apns-fields-for-delivery-and-dismiss-tracking","__idx":17},"children":["APNs fields for delivery and dismiss tracking"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Engage Studio automatically adds two fields to the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["aps"]}," dictionary of every iOS push notification so that your app can track delivery and dismiss events:"]},{"$$mdtype":"Tag","name":"Admonition","attributes":{"type":"info","name":"How these fields work"},"children":[{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["content-available: 1"]}]}," — Marks the notification as a background-update notification. iOS wakes your app briefly in the background on receipt, allowing it to record a ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["delivery"]}," event even when the app is not in the foreground. See Apple's ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"https://developer.apple.com/documentation/usernotifications/pushing-background-updates-to-your-app"},"children":["Pushing background updates to your app"]},"."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["category: default"]}]}," — Associates the notification with a notification category. When your app registers a matching category that allows a custom dismiss action, iOS calls your delegate when the user swipes the notification away, enabling ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["dismiss"]}," tracking. See Apple's ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"https://developer.apple.com/documentation/usernotifications/generating-a-remote-notification"},"children":["Generating a remote notification"]},"."]}]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["These payload fields are sent by Engage Studio automatically — no campaign configuration is required. However, to actually capture delivery and dismiss events your app must complete the ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"#enabling-delivery-and-dismiss-tracking-required-app-side-setup"},"children":["required app-side setup"]}," described below."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"event-tracking","__idx":18},"children":["Event Tracking"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Your app must track the following events and send them to Treasure Data:"]},{"$$mdtype":"Tag","name":"div","attributes":{"className":"md-table-wrapper"},"children":[{"$$mdtype":"Tag","name":"table","attributes":{"className":"md"},"children":[{"$$mdtype":"Tag","name":"thead","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Event Type"},"children":["Event Type"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"When to Track"},"children":["When to Track"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Required Fields"},"children":["Required Fields"]}]}]},{"$$mdtype":"Tag","name":"tbody","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["delivery"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["When notification is received and displayed"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["campaign_id"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["platform"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["time"]}]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["open"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["When user taps the notification"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["campaign_id"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["platform"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["time"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["user_id"]}]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["dismiss"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["When user dismisses the notification"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["campaign_id"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["platform"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["time"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["user_id"]}]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["link_open"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["When user taps a web link"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["campaign_id"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["platform"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["time"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["user_id"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["value"]}," (URL)"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["deeplink_open"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["When user taps a deep link"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["campaign_id"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["platform"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["time"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["user_id"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["value"]}," (URI)"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["token_register"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["When FCM token is obtained or refreshed"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["fcm_token"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["platform"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["time"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["user_id"]}," (if logged in)"]}]}]}]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["All events are automatically sent by the Treasure Data SDK to the configured Treasure Data endpoint. The SDK handles batching, queuing, and retry logic automatically."]},{"$$mdtype":"Tag","name":"Admonition","attributes":{"type":"info","name":"Delivery and dismiss events require app-side setup"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["delivery"]}," event (when the app is in the background) and the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["dismiss"]}," event rely on the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["content-available"]}," and ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["category"]}," fields that Engage Studio adds to the payload. To capture these events, your app must complete the ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"#enabling-delivery-and-dismiss-tracking-required-app-side-setup"},"children":["Enabling Delivery and Dismiss Tracking"]}," setup below."]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["See the ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/products/marketing-cloud/engage-studio/channels/mobile-push/push-events-table"},"children":["Push Events Table"]}," documentation for complete schema details."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"enabling-delivery-and-dismiss-tracking-required-app-side-setup","__idx":19},"children":["Enabling Delivery and Dismiss Tracking (Required App-Side Setup)"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Engage Studio adds ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["content-available: 1"]}," and ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["category: default"]}," to the iOS push payload automatically. To turn these into ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["delivery"]}," and ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["dismiss"]}," events, your app must implement the following."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"1-enable-background-modes","__idx":20},"children":["1. Enable Background Modes"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Enable ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Background Modes → Remote notifications"]}," for your app target, as described in ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"#step-5-configure-capabilities-in-xcode"},"children":["Step 5: Configure Capabilities in Xcode"]},". This allows iOS to wake your app in the background when a notification with ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["content-available: 1"]}," arrives, so you can record a ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["delivery"]}," event."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"2-register-the-default-notification-category","__idx":21},"children":["2. Register the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["default"]}," notification category"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Register a ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["UNNotificationCategory"]}," with the identifier ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["default"]}," and the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":[".customDismissAction"]}," option so iOS notifies your app when a notification is dismissed. Set the category when you configure the notification center (for example, in ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["application(_:didFinishLaunchingWithOptions:)"]},"):"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"swift","header":{"controls":{"copy":{}}},"source":"let defaultCategory = UNNotificationCategory(\n    identifier: \"default\",\n    actions: [],\n    intentIdentifiers: [],\n    options: [.customDismissAction]\n)\nUNUserNotificationCenter.current().setNotificationCategories([defaultCategory])\n","lang":"swift"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["identifier"]}," must match the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["category"]}," value (",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["default"]},") sent in the payload."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"3-track-the-dismiss-event","__idx":22},"children":["3. Track the dismiss event"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["iOS calls ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["userNotificationCenter(_:didReceive:withCompletionHandler:)"]}," with ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["UNNotificationDismissActionIdentifier"]}," as the action identifier when the user swipes the notification away. Track the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["dismiss"]}," event there:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"swift","header":{"controls":{"copy":{}}},"source":"func userNotificationCenter(\n    _ center: UNUserNotificationCenter,\n    didReceive response: UNNotificationResponse,\n    withCompletionHandler completionHandler: @escaping () -> Void\n) {\n    let userInfo = response.notification.request.content.userInfo\n\n    switch response.actionIdentifier {\n    case UNNotificationDismissActionIdentifier:\n        // User dismissed the notification\n        TrackingService.shared.track(event: \"dismiss\", userInfo: userInfo)\n    case UNNotificationDefaultActionIdentifier:\n        // User tapped the notification\n        TrackingService.shared.track(event: \"open\", userInfo: userInfo)\n    default:\n        break\n    }\n\n    completionHandler()\n}\n","lang":"swift"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"4-track-background-delivery","__idx":23},"children":["4. Track background delivery"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["When a notification with ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["content-available: 1"]}," arrives while your app is in the background, iOS calls ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["application(_:didReceiveRemoteNotification:fetchCompletionHandler:)"]},". Record the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["delivery"]}," event there. Guard the call with ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["applicationState != .active"]}," so you do not record a duplicate ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["delivery"]}," event for foreground notifications, which are already tracked in the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["willPresent"]}," delegate:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"swift","header":{"controls":{"copy":{}}},"source":"func application(\n    _ application: UIApplication,\n    didReceiveRemoteNotification userInfo: [AnyHashable: Any],\n    fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void\n) {\n    // Only track background deliveries here; foreground deliveries are\n    // tracked in the willPresent delegate to avoid duplicate events.\n    if application.applicationState != .active {\n        TrackingService.shared.track(event: \"delivery\", userInfo: userInfo)\n    }\n    completionHandler(.newData)\n}\n","lang":"swift"},"children":[]},{"$$mdtype":"Tag","name":"Admonition","attributes":{"type":"info","name":"Reference Implementation"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["See ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["AppDelegate.swift"]}," in the ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"https://github.com/treasure-data/engage-push-notification-sample/tree/main/ios"},"children":["sample repository"]}," for a complete implementation of category registration and delivery/dismiss tracking."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"testing","__idx":24},"children":["Testing"]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"test-on-simulator-ios-13","__idx":25},"children":["Test on Simulator (iOS 13+)"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["iOS Simulator supports push notifications from iOS 13 and Xcode 11.4+:"]},{"$$mdtype":"Tag","name":"ol","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Create a test payload file ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["test-notification.apns"]},":"]}]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"json","header":{"controls":{"copy":{}}},"source":"{\n  \"Simulator Target Bundle\": \"com.example.myapp\",\n  \"aps\": {\n    \"alert\": {\n      \"title\": \"Test Notification\",\n      \"body\": \"This is a test message\"\n    },\n    \"sound\": \"default\",\n    \"badge\": 1\n  },\n  \"campaign_id\": \"test_campaign\",\n  \"deeplink\": \"myapp://test\"\n}\n","lang":"json"},"children":[]},{"$$mdtype":"Tag","name":"ol","attributes":{"start":2},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Send to simulator:"]}]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"bash","header":{"controls":{"copy":{}}},"source":"xcrun simctl push booted com.example.myapp test-notification.apns\n","lang":"bash"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"test-on-physical-device","__idx":26},"children":["Test on Physical Device"]},{"$$mdtype":"Tag","name":"ol","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Get your FCM token from app logs"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Open Firebase Console > Cloud Messaging"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Click ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Send your first message"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Enter title and body"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Click ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Send test message"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Enter your FCM token"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Verify notification appears on device"]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"verify-event-tracking","__idx":27},"children":["Verify Event Tracking"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Query Treasure Data to confirm events are being logged:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"sql","header":{"controls":{"copy":{}}},"source":"SELECT\n  time,\n  type,\n  campaign_id,\n  platform\nFROM mobile.push_events\nWHERE platform = 'ios'\nORDER BY time DESC\nLIMIT 100\n","lang":"sql"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"user-id-association","__idx":28},"children":["User ID Association"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["To link push notification events with specific users, pass the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["user_id"]}," when registering the FCM token."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Implementation Notes:"]}]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Logged-in users"]},": Include ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["user_id"]}," (e.g., customer ID, email hash) in token registration events"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Not logged-in users"]},": Pass ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["nil"]}," for ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["user_id"]}," — Treasure Data will associate the token later when the user logs in"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Name resolution"]},": Treasure Data links events by matching ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["fcm_token"]}," values over time"]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"troubleshooting","__idx":29},"children":["Troubleshooting"]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"notifications-not-received","__idx":30},"children":["Notifications not received"]},{"$$mdtype":"Tag","name":"ol","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Check APNs certificate"]},": Verify APNs authentication key is uploaded to Firebase Console"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Check Bundle ID"]},": Ensure Bundle ID in Xcode matches Firebase registration (case-sensitive)"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Check notification permissions"]},": Verify app has notification permission in Settings > Notifications"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Check device registration"]},": Confirm ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["didRegisterForRemoteNotificationsWithDeviceToken"]}," is called"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Test with Firebase Console"]},": Send test notification directly from Firebase"]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"rich-images-not-displaying","__idx":31},"children":["Rich images not displaying"]},{"$$mdtype":"Tag","name":"ol","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Verify Notification Service Extension"]},": Check extension is properly configured and added to app"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Check image URL"]},": Ensure URL is HTTPS and image is accessible"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Check extension logs"]},": Use Console.app to view extension logs"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Check file size"]},": Large images may timeout (limit ~10MB)"]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"events-not-appearing-in-treasure-data","__idx":32},"children":["Events not appearing in Treasure Data"]},{"$$mdtype":"Tag","name":"ol","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Check write key"]},": Verify ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["TDWriteKey"]}," in Info.plist is correct and active"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Check endpoint"]},": Ensure ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["TDEndpoint"]}," matches your region (US, Tokyo, EU)"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Check table name"]},": Confirm ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["TDDatabase"]}," and ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["TDTable"]}," exist in Treasure Data"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Check SDK initialization"]},": Verify Treasure Data SDK is initialized in AppDelegate"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Enable logging"]},": Add ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["TreasureData.enableLogging()"]}," to see SDK activity"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Force upload"]},": Try calling ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["TreasureData.sharedInstance().uploadEvents()"]}," manually"]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"deep-links-not-working","__idx":33},"children":["Deep links not working"]},{"$$mdtype":"Tag","name":"ol","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Verify URL scheme"]},": Check ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Info.plist"]}," has correct ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["CFBundleURLTypes"]}," configuration"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Test deep link"]},": Use Safari to test: Enter ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["myapp://test"]}," in address bar"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Check scene delegate"]},": Ensure ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["scene(_:openURLContexts:)"]}," is implemented"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Check URI format"]},": Verify deep link starts with your registered scheme"]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"security-best-practices","__idx":34},"children":["Security Best Practices"]},{"$$mdtype":"Tag","name":"ol","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Protect API Keys"]},":"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Never commit actual ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["TDWriteKey"]}," to source control"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Use placeholder values in Info.plist committed to Git"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Document required configuration separately"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Use write-only keys (not master keys)"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Consider using Keychain for production apps"]}]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Validate Deep Links"]},":"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Always validate deep link destinations before navigating"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Implement URL allowlists for sensitive actions"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Sanitize deep link parameters"]}]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Secure Event Data"]},":"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Do not include PII (personally identifiable information) in event payloads"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Use hashed or anonymized user IDs when possible"]}]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Network Security"]},":"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Always use HTTPS for API endpoints"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Implement App Transport Security (ATS)"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Consider certificate pinning for production apps"]}]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"sample-repository","__idx":35},"children":["Sample Repository"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Complete, production-ready implementation:"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"https://github.com/treasure-data/engage-push-notification-sample/tree/main/ios"},"children":["https://github.com/treasure-data/engage-push-notification-sample/tree/main/ios"]}]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The repository includes:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Full source code with inline documentation"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["XcodeGen project configuration"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Swift Package Manager dependency management"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Treasure Data SDK integration examples"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Testing instructions"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Security best practices"]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"implementation-guide","__idx":36},"children":["Implementation Guide"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["This section provides detailed instructions for building and testing the sample application."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"project-structure","__idx":37},"children":["Project Structure"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The sample repository follows this directory structure:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"header":{"controls":{"copy":{}}},"source":"ios/\n├── TDPushSample/\n│   ├── AppDelegate.swift           # Firebase & TD SDK init, notification delegates\n│   ├── SceneDelegate.swift         # Deep link routing\n│   ├── ViewController.swift        # Main UI\n│   ├── TrackingService.swift       # Event tracking with TD SDK\n│   ├── CategoryView.swift          # Category example\n│   ├── ProductDetailView.swift     # Product detail example\n│   ├── Models/                     # Data models\n│   ├── Utils/                      # Utility classes\n│   ├── Assets.xcassets\n│   ├── Info.plist                  # App config & TD settings\n│   └── GoogleService-Info.plist.example  # Firebase config template\n├── NotificationService/             # Extension for rich media\n│   └── NotificationService.swift\n├── project.yml                      # XcodeGen configuration\n└── TDPushSample.xcodeproj/         # Generated by XcodeGen\n"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"build-and-run-instructions","__idx":38},"children":["Build and Run Instructions"]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"prerequisites","__idx":39},"children":["Prerequisites"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["macOS 12.0 or later"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Xcode 14.0 or later"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["XcodeGen installed via Homebrew"]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"setup-steps","__idx":40},"children":["Setup Steps"]},{"$$mdtype":"Tag","name":"ol","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Clone the repository:"]}]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"bash","header":{"controls":{"copy":{}}},"source":"git clone https://github.com/treasure-data/engage-push-notification-sample.git\ncd engage-push-notification-sample/ios\n","lang":"bash"},"children":[]},{"$$mdtype":"Tag","name":"ol","attributes":{"start":2},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Install XcodeGen (if not already installed):"]}]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"bash","header":{"controls":{"copy":{}}},"source":"brew install xcodegen\n","lang":"bash"},"children":[]},{"$$mdtype":"Tag","name":"ol","attributes":{"start":3},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Generate Xcode project:"]}]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"bash","header":{"controls":{"copy":{}}},"source":"xcodegen generate\n","lang":"bash"},"children":[]},{"$$mdtype":"Tag","name":"ol","attributes":{"start":4},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Configure Firebase:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Download ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["GoogleService-Info.plist"]}," from your Firebase project"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Copy it to ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["TDPushSample/GoogleService-Info.plist"]}]}]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Configure Treasure Data:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Open ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["TDPushSample/Info.plist"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Update the following keys with your configuration:",{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["TDWriteKey"]},": Your write-only API key"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["TDDatabase"]},": Your database name (e.g., \"mobile\")"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["TDTable"]},": Your table name (e.g., \"push_events\")"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["TDEndpoint"]},": Your TD endpoint (e.g., \"https://in.treasuredata.com\")"]}]}]}]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Open project in Xcode:"]}]}]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"bash","header":{"controls":{"copy":{}}},"source":"open TDPushSample.xcodeproj\n","lang":"bash"},"children":[]},{"$$mdtype":"Tag","name":"ol","attributes":{"start":7},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Build and run:",{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Select target device/simulator"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Press Cmd+R to build and run"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Swift Package Manager will automatically resolve dependencies"]}]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"testing-workflow","__idx":41},"children":["Testing Workflow"]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"prerequisites-1","__idx":42},"children":["Prerequisites"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Before testing, ensure you have:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"input","attributes":{"checked":false,"type":"checkbox","readOnly":true},"children":[]}," Firebase project with iOS app registered"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"input","attributes":{"checked":false,"type":"checkbox","readOnly":true},"children":[]}," APNs authentication key uploaded to Firebase Console"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"input","attributes":{"checked":false,"type":"checkbox","readOnly":true},"children":[]}," ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["GoogleService-Info.plist"]}," downloaded and added to project"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"input","attributes":{"checked":false,"type":"checkbox","readOnly":true},"children":[]}," Treasure Data database and table created"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"input","attributes":{"checked":false,"type":"checkbox","readOnly":true},"children":[]}," Write-only API key obtained"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"input","attributes":{"checked":false,"type":"checkbox","readOnly":true},"children":[]}," Physical device or iOS 13+ simulator"]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"test-on-simulator-ios-13-1","__idx":43},"children":["Test on Simulator (iOS 13+)"]},{"$$mdtype":"Tag","name":"ol","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Create test payload file ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["test-notification.apns"]},":"]}]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"json","header":{"controls":{"copy":{}}},"source":"{\n  \"Simulator Target Bundle\": \"com.example.myapp\",\n  \"aps\": {\n    \"alert\": {\n      \"title\": \"Test Notification\",\n      \"body\": \"This is a test message\"\n    },\n    \"sound\": \"default\",\n    \"badge\": 1\n  },\n  \"campaign_id\": \"test_campaign\",\n  \"deeplink\": \"myapp://test\",\n  \"image_url\": \"https://example.com/image.jpg\"\n}\n","lang":"json"},"children":[]},{"$$mdtype":"Tag","name":"ol","attributes":{"start":2},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Run app on simulator:"]}]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"bash","header":{"controls":{"copy":{}}},"source":"# Boot simulator\nxcrun simctl boot \"iPhone 15\"\n\n# Build and run\nxcodebuild -workspace MyApp.xcworkspace \\\n  -scheme MyApp \\\n  -destination 'platform=iOS Simulator,name=iPhone 15' \\\n  build\n","lang":"bash"},"children":[]},{"$$mdtype":"Tag","name":"ol","attributes":{"start":3},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Send test notification:"]}]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"bash","header":{"controls":{"copy":{}}},"source":"xcrun simctl push booted com.example.myapp test-notification.apns\n","lang":"bash"},"children":[]},{"$$mdtype":"Tag","name":"ol","attributes":{"start":4},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Verify notification appears and image loads"]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"test-on-physical-device-1","__idx":44},"children":["Test on Physical Device"]},{"$$mdtype":"Tag","name":"ol","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Connect device via USB"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Enable Developer Mode on device:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Settings > Privacy & Security > Developer Mode"]}]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Build and install app from Xcode"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Check Xcode console for FCM token:"]}]}]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"header":{"controls":{"copy":{}}},"source":"FCM token: [your-token-here]\n"},"children":[]},{"$$mdtype":"Tag","name":"ol","attributes":{"start":5},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Send test notification from Firebase Console:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Open Firebase Console > Cloud Messaging"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Click \"Send your first message\""]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Enter title and body"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Click \"Send test message\""]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Paste your FCM token"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Click \"Test\""]}]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Verify notification appears on device"]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"verify-event-tracking-1","__idx":45},"children":["Verify Event Tracking"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Query Treasure Data to confirm events are being logged:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"sql","header":{"controls":{"copy":{}}},"source":"SELECT\n  time,\n  type,\n  campaign_id,\n  platform,\n  user_id\nFROM mobile.push_events\nWHERE platform = 'ios'\n  AND time > td_time_add(now(), '-1h', 'JST')\nORDER BY time DESC\nLIMIT 20\n","lang":"sql"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Expected event sequence:"]},{"$$mdtype":"Tag","name":"ol","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["token_register"]}," - When app launches"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["delivery"]}," - When notification is received"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["open"]}," - When user taps notification"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["link_open"]}," or ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["deeplink_open"]}," - If notification contains links"]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"implementation-checklist","__idx":46},"children":["Implementation Checklist"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Use this checklist when implementing push notifications in your own app:"]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"phase-1-project-setup","__idx":47},"children":["Phase 1: Project Setup"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"input","attributes":{"checked":false,"type":"checkbox","readOnly":true},"children":[]}," Install XcodeGen: ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["brew install xcodegen"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"input","attributes":{"checked":false,"type":"checkbox","readOnly":true},"children":[]}," Create or clone iOS project"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"input","attributes":{"checked":false,"type":"checkbox","readOnly":true},"children":[]}," Generate Xcode project with ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["xcodegen generate"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"input","attributes":{"checked":false,"type":"checkbox","readOnly":true},"children":[]}," Add Push Notifications capability in Xcode"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"input","attributes":{"checked":false,"type":"checkbox","readOnly":true},"children":[]}," Add Background Modes capability (Remote notifications)"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"input","attributes":{"checked":false,"type":"checkbox","readOnly":true},"children":[]}," Configure URL scheme for deep links in Info.plist"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"input","attributes":{"checked":false,"type":"checkbox","readOnly":true},"children":[]}," Download and add ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["GoogleService-Info.plist"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"input","attributes":{"checked":false,"type":"checkbox","readOnly":true},"children":[]}," Configure Treasure Data settings in Info.plist"]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"phase-2-core-components","__idx":48},"children":["Phase 2: Core Components"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"input","attributes":{"checked":false,"type":"checkbox","readOnly":true},"children":[]}," Implement Firebase initialization in ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["AppDelegate"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"input","attributes":{"checked":false,"type":"checkbox","readOnly":true},"children":[]}," Implement Treasure Data SDK initialization in ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["AppDelegate"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"input","attributes":{"checked":false,"type":"checkbox","readOnly":true},"children":[]}," Configure ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["UNUserNotificationCenter"]}," delegate"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"input","attributes":{"checked":false,"type":"checkbox","readOnly":true},"children":[]}," Configure Firebase Messaging delegate"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"input","attributes":{"checked":false,"type":"checkbox","readOnly":true},"children":[]}," Request notification permissions"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"input","attributes":{"checked":false,"type":"checkbox","readOnly":true},"children":[]}," Register for remote notifications"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"input","attributes":{"checked":false,"type":"checkbox","readOnly":true},"children":[]}," Create ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["TrackingService"]}," for event tracking with TD SDK"]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"phase-3-notification-service-extension","__idx":49},"children":["Phase 3: Notification Service Extension"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"input","attributes":{"checked":false,"type":"checkbox","readOnly":true},"children":[]}," Create Notification Service Extension target"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"input","attributes":{"checked":false,"type":"checkbox","readOnly":true},"children":[]}," Implement ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["NotificationService"]}," class"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"input","attributes":{"checked":false,"type":"checkbox","readOnly":true},"children":[]}," Add image download logic"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"input","attributes":{"checked":false,"type":"checkbox","readOnly":true},"children":[]}," Create ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["UNNotificationAttachment"]}," for images"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"input","attributes":{"checked":false,"type":"checkbox","readOnly":true},"children":[]}," Handle extension timeout gracefully"]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"phase-4-event-tracking","__idx":50},"children":["Phase 4: Event Tracking"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"input","attributes":{"checked":false,"type":"checkbox","readOnly":true},"children":[]}," Track ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["delivery"]}," events in ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["willPresent"]}," delegate using TD SDK"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"input","attributes":{"checked":false,"type":"checkbox","readOnly":true},"children":[]}," Register the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["default"]}," notification category with ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":[".customDismissAction"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"input","attributes":{"checked":false,"type":"checkbox","readOnly":true},"children":[]}," Confirm Background Modes (Remote notifications) is enabled for background delivery"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"input","attributes":{"checked":false,"type":"checkbox","readOnly":true},"children":[]}," Track background ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["delivery"]}," events in ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["didReceiveRemoteNotification"]}," using TD SDK"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"input","attributes":{"checked":false,"type":"checkbox","readOnly":true},"children":[]}," Track ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["open"]}," events in ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["didReceive response"]}," delegate using TD SDK"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"input","attributes":{"checked":false,"type":"checkbox","readOnly":true},"children":[]}," Track ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["dismiss"]}," events for ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["UNNotificationDismissActionIdentifier"]}," in ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["didReceive response"]}," using TD SDK"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"input","attributes":{"checked":false,"type":"checkbox","readOnly":true},"children":[]}," Track ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["link_open"]}," events for web links using TD SDK"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"input","attributes":{"checked":false,"type":"checkbox","readOnly":true},"children":[]}," Track ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["deeplink_open"]}," events for app links using TD SDK"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"input","attributes":{"checked":false,"type":"checkbox","readOnly":true},"children":[]}," Track ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["token_register"]}," events on app launch and token refresh using TD SDK"]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"phase-5-deep-link-handling","__idx":51},"children":["Phase 5: Deep Link Handling"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"input","attributes":{"checked":false,"type":"checkbox","readOnly":true},"children":[]}," Implement ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["scene(_:openURLContexts:)"]}," in SceneDelegate"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"input","attributes":{"checked":false,"type":"checkbox","readOnly":true},"children":[]}," Parse deep link URL scheme and path"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"input","attributes":{"checked":false,"type":"checkbox","readOnly":true},"children":[]}," Navigate to appropriate screen based on deep link"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"input","attributes":{"checked":false,"type":"checkbox","readOnly":true},"children":[]}," Handle web links with Safari or SFSafariViewController"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"input","attributes":{"checked":false,"type":"checkbox","readOnly":true},"children":[]}," Validate deep link destinations"]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"phase-6-configuration-and-security","__idx":52},"children":["Phase 6: Configuration and Security"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"input","attributes":{"checked":false,"type":"checkbox","readOnly":true},"children":[]}," Configure ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["TDWriteKey"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["TDDatabase"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["TDTable"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["TDEndpoint"]}," in Info.plist"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"input","attributes":{"checked":false,"type":"checkbox","readOnly":true},"children":[]}," Use placeholder values for API keys in version control"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"input","attributes":{"checked":false,"type":"checkbox","readOnly":true},"children":[]}," Document required configuration separately"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"input","attributes":{"checked":false,"type":"checkbox","readOnly":true},"children":[]}," Implement error handling for TD SDK operations"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"input","attributes":{"checked":false,"type":"checkbox","readOnly":true},"children":[]}," Add logging for debugging using ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["TreasureData.enableLogging()"]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"phase-7-testing","__idx":53},"children":["Phase 7: Testing"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"input","attributes":{"checked":false,"type":"checkbox","readOnly":true},"children":[]}," Test notification delivery on simulator"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"input","attributes":{"checked":false,"type":"checkbox","readOnly":true},"children":[]}," Test notification delivery on physical device"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"input","attributes":{"checked":false,"type":"checkbox","readOnly":true},"children":[]}," Test rich media (images) in notifications"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"input","attributes":{"checked":false,"type":"checkbox","readOnly":true},"children":[]}," Test deep link navigation"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"input","attributes":{"checked":false,"type":"checkbox","readOnly":true},"children":[]}," Test web link opening"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"input","attributes":{"checked":false,"type":"checkbox","readOnly":true},"children":[]}," Verify events appear in Treasure Data"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"input","attributes":{"checked":false,"type":"checkbox","readOnly":true},"children":[]}," Test with background app state"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"input","attributes":{"checked":false,"type":"checkbox","readOnly":true},"children":[]}," Test with force-quit app state"]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"build-troubleshooting","__idx":54},"children":["Build Troubleshooting"]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"no-such-module-firebase-or-no-such-module-treasuredata-error","__idx":55},"children":["\"No such module 'Firebase'\" or \"No such module 'TreasureData'\" Error"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Ensure Swift Package Manager resolved dependencies"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Try: File > Packages > Reset Package Caches"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Clean build folder: Product > Clean Build Folder (Cmd+Shift+K)"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Regenerate project: ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["xcodegen generate"]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"notification-service-extension-not-loading-images","__idx":56},"children":["Notification Service Extension Not Loading Images"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Check image URL is HTTPS"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Verify image is accessible (test URL in browser)"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Check extension logs in Console.app"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Ensure extension target has increased memory limit in scheme settings"]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"events-not-appearing-in-treasure-data-1","__idx":57},"children":["Events Not Appearing in Treasure Data"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Verify ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["TDWriteKey"]}," in Info.plist is correct"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Check ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["TDEndpoint"]}," matches your region"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Confirm ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["TDDatabase"]}," and ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["TDTable"]}," names are correct"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Verify TD SDK is initialized in AppDelegate"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Enable logging: ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["TreasureData.enableLogging()"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Force upload: ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["TreasureData.sharedInstance().uploadEvents()"]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"deep-links-not-opening","__idx":58},"children":["Deep Links Not Opening"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Verify URL scheme in Info.plist matches deep link"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Test deep link from Safari: enter ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["myapp://test"]}," in address bar"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Check ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["scene(_:openURLContexts:)"]}," is implemented in SceneDelegate"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["For iOS 12 and below, implement in AppDelegate instead"]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"next-steps","__idx":59},"children":["Next Steps"]},{"$$mdtype":"Tag","name":"ol","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Clone the sample repository"]}," and review the implementation"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Configure Firebase"]}," following the ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/products/marketing-cloud/engage-studio/channels/mobile-push/mobile-push-setup"},"children":["Mobile Push Setup"]}," guide"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Implement the components"]}," in your iOS app"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Test notification delivery"]}," and event tracking"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Review event data"]}," in the ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/products/marketing-cloud/engage-studio/channels/mobile-push/push-events-table"},"children":["Push Events Table"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Create your first campaign"]}," in ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/products/marketing-cloud/engage-studio/channels/mobile-push"},"children":["Engage Studio"]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"related-documentation","__idx":60},"children":["Related Documentation"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/products/marketing-cloud/engage-studio/channels/mobile-push/mobile-push-setup"},"children":["Mobile Push Setup"]}," - Firebase and APNs configuration"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/products/marketing-cloud/engage-studio/channels/mobile-push/developer-guide-android"},"children":["Android Developer Guide"]}," - Android implementation guide"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/products/marketing-cloud/engage-studio/channels/mobile-push/push-events-table"},"children":["Push Events Table"]}," - Event schema and analytics queries"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/products/marketing-cloud/engage-studio/channels/mobile-push"},"children":["Campaign Creation"]}," - Create Mobile Push campaigns"]}]}]},"headings":[{"value":"iOS Developer Guide","id":"ios-developer-guide","depth":1},{"value":"Overview","id":"overview","depth":2},{"value":"Requirements","id":"requirements","depth":2},{"value":"Architecture Overview","id":"architecture-overview","depth":2},{"value":"1. AppDelegate Configuration","id":"1-appdelegate-configuration","depth":3},{"value":"2. Notification Service Extension","id":"2-notification-service-extension","depth":3},{"value":"3. Tracking Service","id":"3-tracking-service","depth":3},{"value":"4. Deep Link Handler","id":"4-deep-link-handler","depth":3},{"value":"Project Setup","id":"project-setup","depth":2},{"value":"Step 1: Generate Xcode Project with XcodeGen","id":"step-1-generate-xcode-project-with-xcodegen","depth":3},{"value":"Step 2: Add Firebase and Treasure Data SDK","id":"step-2-add-firebase-and-treasure-data-sdk","depth":3},{"value":"Step 3: Configure Firebase","id":"step-3-configure-firebase","depth":3},{"value":"Step 4: Configure Treasure Data in Info.plist","id":"step-4-configure-treasure-data-in-infoplist","depth":3},{"value":"Step 5: Configure Capabilities in Xcode","id":"step-5-configure-capabilities-in-xcode","depth":3},{"value":"Step 6: Create Notification Service Extension (for Rich Media)","id":"step-6-create-notification-service-extension-for-rich-media","depth":3},{"value":"Step 7: Configure Info.plist for Deep Links","id":"step-7-configure-infoplist-for-deep-links","depth":3},{"value":"Data Payload Schema","id":"data-payload-schema","depth":2},{"value":"APNs fields for delivery and dismiss tracking","id":"apns-fields-for-delivery-and-dismiss-tracking","depth":3},{"value":"Event Tracking","id":"event-tracking","depth":2},{"value":"Enabling Delivery and Dismiss Tracking (Required App-Side Setup)","id":"enabling-delivery-and-dismiss-tracking-required-app-side-setup","depth":2},{"value":"1. Enable Background Modes","id":"1-enable-background-modes","depth":3},{"value":"2. Register the default notification category","id":"2-register-the-default-notification-category","depth":3},{"value":"3. Track the dismiss event","id":"3-track-the-dismiss-event","depth":3},{"value":"4. Track background delivery","id":"4-track-background-delivery","depth":3},{"value":"Testing","id":"testing","depth":2},{"value":"Test on Simulator (iOS 13+)","id":"test-on-simulator-ios-13","depth":3},{"value":"Test on Physical Device","id":"test-on-physical-device","depth":3},{"value":"Verify Event Tracking","id":"verify-event-tracking","depth":3},{"value":"User ID Association","id":"user-id-association","depth":2},{"value":"Troubleshooting","id":"troubleshooting","depth":2},{"value":"Notifications not received","id":"notifications-not-received","depth":3},{"value":"Rich images not displaying","id":"rich-images-not-displaying","depth":3},{"value":"Events not appearing in Treasure Data","id":"events-not-appearing-in-treasure-data","depth":3},{"value":"Deep links not working","id":"deep-links-not-working","depth":3},{"value":"Security Best Practices","id":"security-best-practices","depth":2},{"value":"Sample Repository","id":"sample-repository","depth":2},{"value":"Implementation Guide","id":"implementation-guide","depth":2},{"value":"Project Structure","id":"project-structure","depth":3},{"value":"Build and Run Instructions","id":"build-and-run-instructions","depth":3},{"value":"Prerequisites","id":"prerequisites","depth":4},{"value":"Setup Steps","id":"setup-steps","depth":4},{"value":"Testing Workflow","id":"testing-workflow","depth":3},{"value":"Prerequisites","id":"prerequisites-1","depth":4},{"value":"Test on Simulator (iOS 13+)","id":"test-on-simulator-ios-13-1","depth":4},{"value":"Test on Physical Device","id":"test-on-physical-device-1","depth":4},{"value":"Verify Event Tracking","id":"verify-event-tracking-1","depth":4},{"value":"Implementation Checklist","id":"implementation-checklist","depth":3},{"value":"Phase 1: Project Setup","id":"phase-1-project-setup","depth":4},{"value":"Phase 2: Core Components","id":"phase-2-core-components","depth":4},{"value":"Phase 3: Notification Service Extension","id":"phase-3-notification-service-extension","depth":4},{"value":"Phase 4: Event Tracking","id":"phase-4-event-tracking","depth":4},{"value":"Phase 5: Deep Link Handling","id":"phase-5-deep-link-handling","depth":4},{"value":"Phase 6: Configuration and Security","id":"phase-6-configuration-and-security","depth":4},{"value":"Phase 7: Testing","id":"phase-7-testing","depth":4},{"value":"Build Troubleshooting","id":"build-troubleshooting","depth":3},{"value":"\"No such module 'Firebase'\" or \"No such module 'TreasureData'\" Error","id":"no-such-module-firebase-or-no-such-module-treasuredata-error","depth":4},{"value":"Notification Service Extension Not Loading Images","id":"notification-service-extension-not-loading-images","depth":4},{"value":"Events Not Appearing in Treasure Data","id":"events-not-appearing-in-treasure-data-1","depth":4},{"value":"Deep Links Not Opening","id":"deep-links-not-opening","depth":4},{"value":"Next Steps","id":"next-steps","depth":2},{"value":"Related Documentation","id":"related-documentation","depth":2}],"frontmatter":{"seo":{"title":"iOS Developer Guide","description":"Comprehensive iOS developer guide for integrating Engage Studio Mobile Push notifications, covering APNs token management, rich notifications, and event tracking for mobile apps."}},"lastModified":"2026-06-17T07:22:53.000Z","pagePropGetterError":{"message":"","name":""}},"slug":"/products/marketing-cloud/engage-studio/channels/mobile-push/developer-guide-ios","userData":{"isAuthenticated":false,"teams":["anonymous"]},"isPublic":true}