Ánh xạ giá trị chuyển đổi SKAdNetwork: Tự động hóa lược đồ SKAN động

opoinstall
2026-08-25
5 min read

MMP ánh xạ các lược đồ SKAdNetwork tự động như thế nào? Đối tác đo lường di động (MMP) hoặc hệ thống phân bổ tự động hóa việc ánh xạ lược đồ SKAdNetwork bằng cách dịch các sự kiện trong ứng dụng và cấp doanh thu thành các lược đồ cấu hình JSON có phiên bản động trên một bảng điều khiển tập trung. SDK di động truy xuất cấu hình này khi khởi chạy và đánh giá các quy tắc chuyển đổi cục bộ tại thời điểm chạy, cho phép các thay đổi quy tắc chuyển đổi được hỗ trợ có hiệu lực mà không yêu cầu phát hành bản dựng ứng dụng nhị phân mới.

Lược đồ giá trị chuyển đổi SKAdNetwork là một tập hợp quy tắc cấp nhà cung cấp hoặc cấp ứng dụng, ánh xạ các hành vi của người dùng trong ứng dụng—chẳng hạn như giao dịch doanh thu, mốc hướng dẫn hoặc mức độ tương tác với tính năng—với các giá trị chi tiết 6-bit của Apple (từ 0 đến 63) và các giá trị thô 3 cấp (low, medium, high). Kiến trúc ánh xạ động phân phối các tệp cấu hình có phiên bản từ máy chủ đám mây đến SDK khách, loại bỏ nhu cầu mã hóa cứng logic chuyển đổi trong các tệp nhị phân ứng dụng iOS đã biên dịch.

Thuật ngữ Định nghĩa
SKAdNetwork Khung cấp nền tảng của Apple dành cho việc phân bổ chiến dịch tiếp thị bảo vệ quyền riêng tư.
Lược đồ giá trị chuyển đổi Cấu hình do nhà cung cấp hoặc ứng dụng xác định nhằm ánh xạ các mốc sự kiện trong ứng dụng thành giá trị chi tiết và giá trị thô.
Ánh xạ lược đồ động Việc phân phối tự động và đánh giá thời gian chạy các quy tắc chuyển đổi thông qua SDK.
Khóa cửa sổ Một tham số API (lockWindow: true) giúp hoàn tất cửa sổ chuyển đổi đang hoạt động sớm hơn.

Kiến trúc ánh xạ giá trị chuyển đổi SKAdNetwork tự động

Phân định lớp nền tảng Apple khỏi lớp lược đồ nhà cung cấp

Để thiết kế một công cụ giá trị chuyển đổi mạnh mẽ, các nhóm kỹ thuật phải tách biệt các quy tắc khung nguyên bản của Apple khỏi các lớp trừu tượng lược đồ cấp nhà cung cấp:

  • Lớp nền tảng Apple: Quản lý các nguyên thủy của hệ điều hành cốt lõi, bao gồm ba cửa sổ chuyển đổi tuần tự (Ngày 0–2, Ngày 3–7, Ngày 8–35 sau lần khởi chạy đầu tiên), giá trị chi tiết 6-bit (0–63), giá trị thô (low, medium, high), các cấp dữ liệu bài đăng (postback) và API SKAdNetwork.updatePostbackConversionValue.
  • Lớp lược đồ nhà cung cấp: Bao gồm các quy tắc kinh doanh do ứng dụng xác định, chẳng hạn như phân khúc doanh thu, tiến trình phễu hướng dẫn, phân bổ cờ bitwise, đồng bộ hóa JSON từ xa và đánh giá quy tắc phía máy khách.
┌────────────────────────────────────────┐
│                           Vendor Schema Layer                                  │
│  [MMP / Analytics Console] ──► [Publishes Versioned JSON Configuration]     │
│                                              │                                │
│  [Client Mobile SDK]       ──► [Evaluates In-App Events Locally in Memory]  │
└──────────────────────────────────────┬─┘
                                       │ (Calculates Fine, Coarse, & Lock)
                                       ▼
┌────────────────────────────────────────┐
│                           Apple Platform Layer                                 │
│  [StoreKit Framework]      ──► [SKAdNetwork.updatePostbackConversionValue]  │
│  [Operating System]        ──► [Manages Conversion Windows & Timers]        │
│  [System]                  ──► [Prepares and Sends Signed Postback]         │
└────────────────────────────────────────┘

Dynamic SKAN schema mapping from MMP console to StoreKit

Những cạm bẫy của logic chuyển đổi mã hóa cứng

Việc mã hóa cứng logic chuyển đổi trực tiếp bên trong mục tiêu ứng dụng iOS tạo ra những hạn chế lớn về mặt vận hành:

  • Phụ thuộc vào quy trình duyệt App Store: Bất kỳ sửa đổi nào đối với ngưỡng doanh thu, trọng số sự kiện hoặc trình kích hoạt khóa cửa sổ đều yêu cầu toàn bộ chu kỳ phát hành bản dựng nhị phân.
  • Phân mảnh phiên bản: Nhiều phiên bản ứng dụng lịch sử trong môi trường sản xuất truyền tải ngữ nghĩa chuyển đổi mâu thuẫn nhau, làm hỏng các mô hình báo cáo hạ nguồn.
  • Tính kém linh hoạt trong tối ưu hóa: Các nhóm tăng trưởng không thể điều chỉnh chiến lược chuyển đổi giữa các chiến dịch tập trung vào tương tác và tập trung vào kiếm tiền để phản hồi hiệu suất tiếp thị theo thời gian thực.

Pipeline phân phối cấu hình động

Kiến trúc ánh xạ tự động tách biệt logic chuyển đổi khỏi tệp nhị phân đã biên dịch thông qua một quy trình nhiều giai đoạn:

  1. Cấu hình bảng điều khiển: Các nhà tiếp thị và chuyên gia phân tích cấu hình trọng số sự kiện, cấp tiền tệ và quy tắc khóa cửa sổ trên một bảng điều khiển tập trung.
  2. Quản lý phiên bản và ghim lược đồ: Máy chủ xuất bản một gói cấu hình JSON có phiên bản. Để ngăn chặn sự sai lệch ngữ nghĩa trong vòng đời chuyển đổi 35 ngày của người dùng, việc triển khai nhà cung cấp mạnh mẽ sẽ ghim cấu hình lược đồ hoạt động được thiết lập trong cửa sổ chuyển đổi ban đầu, đảm bảo rằng các quy tắc ánh xạ chính xác vẫn khả dụng ngay cả khi khởi động lại ứng dụng.
  3. Tiếp nhận và lưu bộ nhớ đệm phía máy khách: SDK di động tải xuống lược đồ hoạt động khi khởi ứng dụng và lưu vào bộ nhớ đệm cả gói cấu hình lẫn siêu dữ liệu phiên bản trong bộ nhớ cục bộ bền vững.
  4. Đánh giá quy tắc cục bộ: Khi các sự kiện trong ứng dụng xảy ra, SDK sẽ đánh giá chúng dựa trên tập quy tắc được lưu đệm cục bộ mà không thêm yêu cầu cấu hình từ xa đồng bộ vào luồng thực thi sự kiện.

Hardcoded SKAN logic versus dynamic schema configuration

Xem thêm: SKAdNetwork ──> Kiến trúc phân bổ di động

Thiết kế lược đồ giá trị chuyển đổi động qua các cửa sổ SKAN 4.0

Phân chia lược đồ đa cửa sổ

SKAdNetwork 4.0 cấu trúc việc đo lường chuyển đổi qua ba cửa sổ tuần tự neo theo lần khởi chạy đầu tiên của ứng dụng:

  • Cửa sổ 1 (Ngày 0–2): 48 giờ đầu tiên sau lần khởi chạy đầu tiên.
  • Cửa sổ 2 (Ngày 3–7): Từ giờ thứ 48 đến giờ thứ 168 sau lần khởi chạy đầu tiên.
  • Cửa sổ 3 (Ngày 8–35): Từ giờ thứ 168 đến giờ thứ 840 sau lần khởi chạy đầu tiên.

Một công cụ lược đồ động phân chia các quy tắc qua các cửa sổ này, thực hiện tính toán giá trị thích hợp dựa trên thời gian trôi qua kể từ khi khởi chạy ứng dụng ban đầu.

Cửa sổ 1 (Ngày 0–2): Cấu trúc giá trị chi tiết và giá trị thô

Cửa sổ 1 là cửa sổ chuyển đổi duy nhất đủ điều kiện tiết lộ các giá trị chuyển đổi chi tiết. Cấu hình cho Cửa sổ 1 xác định hai phép ánh xạ đồng thời:

  • Ánh xạ chi tiết (0–63): Các quy tắc độ phân giải cao nắm bắt các cấp độ kiếm tiền ban đầu, các mốc hướng dẫn hoặc điểm số tương tác tổng hợp.
  • Ánh xạ thô (low, medium, high): Các trạng thái dự phòng có độ chi tiết thấp hơn được tiết lộ khi cấp dữ liệu bài đăng được chỉ định không cho phép báo cáo chi tiết.

Cửa sổ 2 (Ngày 3–7) và 3 (Ngày 8–35): Theo dõi vòng đời dạng thô

Bài đăng thứ hai và thứ ba không hiển thị các giá trị chuyển đổi chi tiết; đối với các cấp dữ liệu đủ điều kiện, chúng chỉ tiết lộ các giá trị thô.

Các lược đồ cho Cửa sổ 2 và 3 tập trung vào tỷ lệ giữ chân dài hạn và các mốc gia hạn đăng ký:

  • Ánh xạ thô cửa sổ 2: Đánh giá tỷ lệ giữ chân ở giữa phễu (ví dụ: low = Hoạt động trong Ngày 3–7; medium = Hoàn thành 3 phiên; high = Mua lại hoặc dùng thử đã chuyển đổi).
  • Ánh xạ thô cửa sổ 3: Đánh giá tỷ lệ giữ chân đuôi dài và gia hạn thuê bao (ví dụ: low = Được giữ chân Ngày 8–35; medium = Đạt mốc cấp độ; high = Người đăng ký trả phí hoạt động).

Các nhà phát triển cấu hình lược đồ chuyển đổi có thể tham khảo tài liệu ánh xạ chuyển đổi SKAN để biết các hướng dẫn kỹ thuật về cấu trúc quy tắc đa cửa sổ.

SKAN 4 conversion windows fine and coarse value mapping


Mô hình mã hóa do nhà cung cấp xác định: Phân đoạn doanh thu, phễu và logic Bitwise

Các mô hình mã hóa này đại diện cho các mẫu thiết kế cấp nhà cung cấp và cấp ứng dụng hơn là các loại lược đồ do Apple quy định.

Lược đồ dựa trên doanh thu

Lược đồ doanh thu phân bổ các giá trị chi tiết có sẵn trên các khoản tiền mua tích lũy:

  • Phân đoạn tuyến tính (Linear Bucketing): Chia phạm vi doanh thu thành các khoảng bằng nhau (ví dụ: 64 phân đoạn với bước tăng $1.50 lên đến $96.00). Lý tưởng cho các ứng dụng có quy mô giao dịch có thể dự đoán.
  • Phân đoạn theo hàm logarit (Logarithmic Bucketing): Phân bổ các phân đoạn chi tiết cho các giao dịch chi phí thấp trong khi mở rộng phạm vi phân đoạn cho các giao dịch giá trị cao (ví dụ: Giá trị 1–20 bao gồm $0.99–$19.99; Giá trị 21–50 bao gồm $20.00–$100.00; Giá trị 51–63 bao gồm $100.00–$1000.00+).
  • Phân đoạn dựa trên phân vị (Percentile-Based Bucketing): Ánh xạ phân phối mua hàng lịch sử của người dùng thành các phân khúc nhóm (cohort) dựa trên các đường cong kiếm tiền thực nghiệm.

Lược đồ tiến triển phễu và tính định hướng giá trị

Trong SKAdNetwork 3 trở về trước, Apple yêu cầu các giá trị chuyển đổi tăng một cách đơn điệu. Trong SKAdNetwork 4.0, Apple đã loại bỏ hạn chế này, cho phép các giá trị chuyển đổi trong Cửa sổ 1 tăng hoặc giảm qua các lần gọi API tiếp theo.

Tuy nhiên, nhiều lược đồ phân bổ vẫn cố ý thực thi sự tiến triển đơn điệu như một quy ước thiết kế cấp nhà cung cấp để đảm bảo rằng các giá trị cao hơn đại diện cho kết quả thương mại mạnh mẽ hơn:

  • Giá trị 0: Đã cài đặt và mở ứng dụng.
  • Giá trị 10: Hoàn tất đăng ký tài khoản.
  • Giá trị 20: Hoàn thành hướng dẫn sử dụng.
  • Giá trị 30: Đã thêm phương thức thanh toán.
  • Giá trị 45: Đã thêm sản phẩm vào giỏ hàng.
  • Giá trị 63: Hoàn tất thanh toán ban đầu.

Lược đồ phân loại Bitwise

Lược đồ Bitwise xử lý số nguyên 6-bit (26=642^6 = 64) như sáu cờ boolean độc lập (b5b4b3b2b1b0b_5 b_4 b_3 b_2 b_1 b_0):

Vị trí Bit Trọng số nhị phân Hành vi trong ứng dụng được ánh xạ
Bit 0 (b0b_0) 1 (0b000001) Người dùng hoàn tất đăng ký
Bit 1 (b1b_1) 2 (0b000010) Người dùng bật thông báo đẩy
Bit 2 (b2b_2) 4 (0b000100) Người dùng thêm sản phẩm vào danh sách yêu thích
Bit 3 (b3b_3) 8 (0b001000) Người dùng chia sẻ liên kết giới thiệu
Bit 4 (b4b_4) 16 (0b010000) Người dùng hoàn tất giao dịch mua trong ứng dụng
Bit 5 (b5b_5) 32 (0b100000) Người dùng đăng ký bản dùng thử cao cấp

Gói JSON có phiên bản bên dưới minh họa tài liệu cấu hình động đa cửa sổ:

{
  "schema_version": "4.0.1",
  "app_id": "1234567890",
  "currency": "USD",
  "windows": {
    "window_1": {
      "mode": "hybrid_revenue_and_funnel",
      "fine_mapping": [
        { "event": "app_open", "min_revenue_cents": 0, "fine_value": 0, "lock": false },
        { "event": "registration_complete", "min_revenue_cents": 0, "fine_value": 10, "lock": false },
        { "event": "tutorial_complete", "min_revenue_cents": 0, "fine_value": 20, "lock": false },
        { "event": "purchase", "min_revenue_cents": 99, "fine_value": 30, "lock": false },
        { "event": "purchase", "min_revenue_cents": 999, "fine_value": 45, "lock": false },
        { "event": "purchase", "min_revenue_cents": 4999, "fine_value": 63, "lock": true }
      ],
      "coarse_mapping": {
        "low": { "events": ["app_open", "registration_complete"] },
        "medium": { "events": ["tutorial_complete"] },
        "high": { "events": ["purchase"] }
      }
    },
    "window_2": {
      "mode": "coarse_retention_and_monetization",
      "coarse_mapping": {
        "low": { "events": ["app_open"], "lock": false },
        "medium": { "events": ["session_milestone"], "lock": false },
        "high": { "events": ["repeat_purchase"], "lock": true }
      }
    },
    "window_3": {
      "mode": "coarse_long_tail_ltv",
      "coarse_mapping": {
        "low": { "events": ["app_open"], "lock": false },
        "medium": { "events": ["level_milestone"], "lock": false },
        "high": { "events": ["subscription_active"], "lock": true }
      }
    }
  }
}

Cấu hình SDK động: Tiếp nhận và đánh giá cấu hình từ xa tại thời điểm chạy

Cơ chế đánh giá quy tắc phía máy khách

Các SDK phân bổ đánh giá các quy tắc chuyển đổi cục bộ trong thời gian chạy của ứng dụng:

  • Không có yêu cầu tải cấu hình từ xa đồng bộ trên luồng sự kiện: Các hành động trong ứng dụng kích hoạt việc đánh giá cục bộ trên bộ nhớ dựa trên tập quy tắc đang hoạt động, gọi các API StoreKit ngay lập tức mà không chặn việc thực thi ứng dụng.
  • Giảm thiểu dữ liệu: Đối với đường dẫn cập nhật chuyển đổi SKAdNetwork được hiển thị ở đây, dữ liệu đầu vào sự kiện thô có thể được đánh giá cục bộ và chỉ các giá trị chuyển đổi kết quả mới cần được chuyển đến StoreKit. Điều này tự bản thân nó không mô tả hoặc giới hạn các luồng dữ liệu phân tích khác do SDK thực hiện.

Xử lý trạng thái ngoại tuyến và lưu giữ cục bộ

Khi một ứng dụng khởi chạy ngoại tuyến hoặc trong điều kiện mạng kém:

  1. SDK khởi tạo mốc thời gian khởi chạy đầu tiên một cách độc lập trong bộ lưu trữ cục bộ.
  2. SDK tải lược đồ cấu hình đã ghim từ bộ lưu trữ cục bộ bền vững, xác minh rằng tải trọng được lưu đệm khớp với phiên bản lược đồ đã ghim.
  3. Nếu các sự kiện trong ứng dụng xảy ra khi ngoại tuyến, SDK sẽ đánh giá chúng dựa trên tập quy tắc được lưu đệm và gọi API cập nhật StoreKit ngay lập tức.
  4. Việc chuẩn bị và gửi bài đăng (postback) do hệ thống quản lý và diễn ra không đồng bộ; ứng dụng không cần phải tự gửi các bài đăng này.

Việc triển khai Swift bên dưới minh họa một công cụ đánh giá lược đồ đa cửa sổ tính toán các giá trị chi tiết và thô, quản lý trạng thái khóa dành riêng cho cửa sổ, duy trì cấu hình lược đồ đã ghim và cam kết cập nhật trạng thái chỉ khi thực thi StoreKit thành công:

import Foundation
import StoreKit

// MARK: - Schema Configuration Models

struct SKANSchemaConfig: Codable {
    let schemaVersion: String
    let appId: String
    let currency: String
    let windows: SchemaWindows

    enum CodingKeys: String, CodingKey {
        case schemaVersion = "schema_version"
        case appId = "app_id"
        case currency, windows
    }
}

struct SchemaWindows: Codable {
    let window1: Window1Config
    let window2: WindowCoarseConfig
    let window3: WindowCoarseConfig

    enum CodingKeys: String, CodingKey {
        case window1 = "window_1"
        case window2 = "window_2"
        case window3 = "window_3"
    }
}

struct Window1Config: Codable {
    let mode: String
    let fineMapping: [FineRule]
    let coarseMapping: CoarseRuleGroup

    enum CodingKeys: String, CodingKey {
        case mode
        case fineMapping = "fine_mapping"
        case coarseMapping = "coarse_mapping"
    }
}

struct FineRule: Codable {
    let event: String
    let minRevenueCents: Int
    let fineValue: Int
    let lock: Bool

    enum CodingKeys: String, CodingKey {
        case event
        case minRevenueCents = "min_revenue_cents"
        case fineValue = "fine_value"
        case lock
    }
}

struct WindowCoarseConfig: Codable {
    let mode: String
    let coarseMapping: [String: CoarseRule]

    enum CodingKeys: String, CodingKey {
        case mode
        case coarseMapping = "coarse_mapping"
    }
}

struct CoarseRuleGroup: Codable {
    let low: CoarseRule
    let medium: CoarseRule
    let high: CoarseRule
}

struct CoarseRule: Codable {
    let events: [String]?
    let lock: Bool?
}

// MARK: - Multi-Window SKAN 4.0 Schema Engine

final class SKANSchemaEngine {

    static let shared = SKANSchemaEngine()
    private init() {}

    private var activeSchema: SKANSchemaConfig?
    private var firstLaunchDate: Date?
    private var lockedWindows = Set<Int>()
    private var lastRecordedFineValue: Int = 0
    private var pinnedSchemaVersion: String?

    /// Initializes the first-launch timestamp anchor independently of remote configuration fetches
    func initializeLifecycleAnchor() {
        let defaults = UserDefaults.standard
        if let storedLaunch = defaults.object(forKey: "skan_first_launch_date") as? Date {
            self.firstLaunchDate = storedLaunch
        } else {
            let now = Date()
            self.firstLaunchDate = now
            defaults.set(now, forKey: "skan_first_launch_date")
        }

        let lockedArray = defaults.array(forKey: "skan_locked_windows") as? [Int] ?? []
        self.lockedWindows = Set(lockedArray)
        self.lastRecordedFineValue = defaults.integer(forKey: "skan_last_fine_value")
        self.pinnedSchemaVersion = defaults.string(forKey: "skan_pinned_schema_version")

        // Restore previously cached schema payload if it matches the pinned version
        if let pinnedVersion = self.pinnedSchemaVersion,
           let cachedData = defaults.data(forKey: "skan_cached_schema_payload"),
           let cachedSchema = try? JSONDecoder().decode(SKANSchemaConfig.self, from: cachedData),
           cachedSchema.schemaVersion == pinnedVersion {
            self.activeSchema = cachedSchema
        }
    }

    /// Loads active schema, persisting the pinned payload to maintain consistency across the 35-day lifecycle
    func configure(schema: SKANSchemaConfig) {
        let defaults = UserDefaults.standard
        if let pinned = pinnedSchemaVersion {
            // If already pinned, accept only schemas matching the pinned version
            if pinned == schema.schemaVersion {
                self.activeSchema = schema
                if let data = try? JSONEncoder().encode(schema) {
                    defaults.set(data, forKey: "skan_cached_schema_payload")
                }
            }
        } else {
            // Pin the initial schema version for this lifecycle
            self.activeSchema = schema
            self.pinnedSchemaVersion = schema.schemaVersion
            defaults.set(schema.schemaVersion, forKey: "skan_pinned_schema_version")
            if let data = try? JSONEncoder().encode(schema) {
                defaults.set(data, forKey: "skan_cached_schema_payload")
            }
        }
    }

    /// Determines the active conversion window based on elapsed time from first launch
    private var currentWindowIndex: Int {
        guard let firstLaunch = firstLaunchDate else { return 0 }
        let elapsedHours = Date().timeIntervalSince(firstLaunch) / 3600.0

        switch elapsedHours {
        case 0.0..<48.0:
            return 1
        case 48.0..<168.0:
            return 2
        case 168.0...840.0:
            return 3
        default:
            return 0 // Window closed (>35 days)
        }
    }

    /// Evaluates an in-app event against the active schema for the current window
    func trackEvent(name: String, revenueCents: Int = 0) {
        guard #available(iOS 16.1, *),
              let schema = activeSchema else { return }

        let window = currentWindowIndex
        guard window >= 1 && window <= 3, !lockedWindows.contains(window) else { return }

        var targetFineValue: Int?
        var targetCoarseValue: SKAdNetwork.CoarseConversionValue?
        var shouldLock = false
        var matchedRule = false

        if window == 1 {
            // Window 1: Evaluate fine-grained rules with highest-threshold precedence
            let matchingFineRules = schema.windows.window1.fineMapping
                .filter { $0.event == name && revenueCents >= $0.minRevenueCents }
                .sorted { $0.minRevenueCents < $1.minRevenueCents }

            if let highestRule = matchingFineRules.last {
                targetFineValue = highestRule.fineValue
                if highestRule.lock { shouldLock = true }
                matchedRule = true
            }

            // Window 1: Evaluate coarse-grained rules explicitly
            if schema.windows.window1.coarseMapping.high.events?.contains(name) == true {
                targetCoarseValue = .high
                matchedRule = true
            } else if schema.windows.window1.coarseMapping.medium.events?.contains(name) == true {
                targetCoarseValue = .medium
                matchedRule = true
            } else if schema.windows.window1.coarseMapping.low.events?.contains(name) == true {
                targetCoarseValue = .low
                matchedRule = true
            }
        } else {
            // Windows 2 & 3: Evaluate coarse rules only
            let coarseConfig = (window == 2) ? schema.windows.window2 : schema.windows.window3
            
            if let highRule = coarseConfig.coarseMapping["high"], highRule.events?.contains(name) == true {
                targetCoarseValue = .high
                if highRule.lock == true { shouldLock = true }
                matchedRule = true
            } else if let medRule = coarseConfig.coarseMapping["medium"], medRule.events?.contains(name) == true {
                targetCoarseValue = .medium
                if medRule.lock == true { shouldLock = true }
                matchedRule = true
            } else if let lowRule = coarseConfig.coarseMapping["low"], lowRule.events?.contains(name) == true {
                targetCoarseValue = .low
                if lowRule.lock == true { shouldLock = true }
                matchedRule = true
            }
        }

        // If no explicit rule matched for this event, do not trigger a StoreKit update
        guard matchedRule else { return }

        let fineToSubmit = targetFineValue ?? (window == 1 ? lastRecordedFineValue : 0)
        let clampedFine = max(0, min(63, fineToSubmit))
        let coarseToSubmit = targetCoarseValue ?? .low

        // Dispatch StoreKit conversion update
        // Note: StoreKit ignores the fineValue parameter after Window 1
        SKAdNetwork.updatePostbackConversionValue(
            clampedFine,
            coarseValue: coarseToSubmit,
            lockWindow: shouldLock
        ) { [weak self] error in
            guard let self = self else { return }
            if let error = error {
                print("StoreKit conversion update failed: \(error.localizedDescription)")
            } else {
                // Commit local state only after StoreKit successfully accepts the update
                DispatchQueue.main.async {
                    if window == 1 {
                        self.lastRecordedFineValue = clampedFine
                        UserDefaults.standard.set(clampedFine, forKey: "skan_last_fine_value")
                    }
                    if shouldLock {
                        self.lockedWindows.insert(window)
                        UserDefaults.standard.set(Array(self.lockedWindows), forKey: "skan_locked_windows")
                    }
                    print("SKAN 4.0 update succeeded: Window=\(window), Fine=\(clampedFine), Coarse=\(coarseToSubmit.rawValue), Locked=\(shouldLock)")
                }
            }
        }
    }
}

SKAN lockWindow timing and early postback preparation

Tự động hóa việc thực thi lockWindow để đẩy nhanh quá trình chuẩn bị bài đăng

Cơ chế vận hành của tham số lockWindow

Khi một ứng dụng gọi hàm updatePostbackConversionValue(_:coarseValue:lockWindow:) với thiết lập lockWindow: true, bản cập nhật này sẽ trở thành cập nhật giá trị chuyển đổi cuối cùng cho cửa sổ đang hoạt động. Hệ điều hành chuẩn bị bài đăng ngay lập tức và bỏ qua các bản cập nhật giá trị chuyển đổi bổ sung trong phần còn lại của cửa sổ đó.

Default Window 1 (No Lock):
[First Launch] ─────────────── 48 Hours Open ───────────────► [Closes] ──► Delay (24-48h) ──► Postback 1

Locked Window 1 (Purchase at Hour 6):
[First Launch] ── 6h (Lock: true) ──► [Conversion Locked / Postback Prepared] ──► Delay (24-48h) ──► Postback 1 Sent Sooner

Đánh đổi chiến lược trong việc tự động khóa cửa sổ

  • Gửi bài đăng nhanh chóng: Hoàn tất chuyển đổi sớm cho phép thời gian trễ ngẫu nhiên của bài đăng từ Apple bắt đầu ngay lập tức, chuyển dữ liệu chuyển đổi đến các mạng tiếp thị sớm hơn.
  • Tính độc lập của cửa sổ: Việc khóa cửa sổ hiện tại không làm dịch chuyển thời điểm bắt đầu của cửa sổ tiếp theo về phía trước; Cửa sổ 2 vẫn bắt đầu vào Ngày 3 bất kể Cửa sổ 1 được khóa vào lúc nào.
  • Cắt ngắn thời gian quan sát: Khi cửa sổ bị khóa, hệ thống sẽ bỏ qua các lệnh gọi cập nhật giá trị chuyển đổi tiếp theo trong phần còn lại của cửa sổ chuyển đổi đó. Các sự kiện trong ứng dụng có thể tiếp tục diễn ra, nhưng chúng không thể thay đổi trạng thái chuyển đổi SKAdNetwork của cửa sổ đó nữa.

Phối hợp các lược đồ SKAN với AdAttributionKit

Hệ thống phân bổ đang phát triển của Apple

Apple hiện khuyến nghị sử dụng AdAttributionKit cho các chiến dịch quảng cáo ứng dụng trên App Store và các chợ ứng dụng thay thế. SKAdNetwork vẫn giữ vai trò quan trọng đối với các tích hợp hiện có và khả năng tương thích ngược, vì vậy các công cụ ánh xạ động nên giữ cho lớp quy tắc kinh doanh tách biệt khỏi các API chuyển đổi dành riêng cho từng khung:

  • Các chiều giá trị chia sẻ: Cả hai khung đều đánh giá các giá trị chi tiết 6-bit (từ 0 đến 63) và các giá trị thô 3 cấp (low, medium, high).
  • Các lớp API riêng biệt: SKAdNetwork sử dụng SKAdNetwork.updatePostbackConversionValue, trong khi AdAttributionKit sử dụng Postback.updateConversionValue.
  • Hành vi bắc cầu: Nếu một tích hợp hỗ trợ cả hai khung, Apple khuyến nghị gọi API cập nhật chuyển đổi của cả hai khung, đồng thời tính đến hành vi bắc cầu từ SKAdNetwork sang AdAttributionKit đã được tài liệu hóa.

Ma trận quyết định so sánh: Logic phía máy khách mã hóa cứng và Cấu hình động

Chiều đánh giá Logic phía máy khách mã hóa cứng Cấu hình lược đồ động
Tốc độ sửa đổi lược đồ Yêu cầu duyệt App Store (Từ vài ngày đến vài tuần) Cập nhật từ xa cho các thay đổi quy tắc được hỗ trợ mà không yêu cầu phát hành bản dựng mới
Khả năng kiểm thử & lặp lại linh hoạt Độ ma sát cao / Chi phí kỹ thuật lớn Thử nghiệm lược đồ có kiểm soát với các quy tắc được cô lập theo phiên bản và nhóm
Phối hợp đa cửa sổ Hệ thống trạng thái thủ công phức tạp trong Swift Công cụ tự động nhận biết vòng đời
Tự động khóa cửa sổ Trình kích hoạt quy tắc cố định, kém linh hoạt Quy tắc khóa động được kích hoạt theo sự kiện
Sự tương đồng giữa các khung Mã bị phân mảnh trên các khung Ma trận cấu hình đám mây thống nhất

Câu hỏi thường gặp (FAQ)

Điều gì xảy ra nếu người dùng kích hoạt nhiều sự kiện được ánh xạ tới các giá trị chuyển đổi khác nhau?
Trong SKAdNetwork 4.0, Apple cho phép các giá trị chuyển đổi trong Cửa sổ 1 tăng hoặc giảm qua các lần gọi liên tiếp. Tuy nhiên, lược đồ phân bổ có thể thực thi sự tiến triển đơn điệu như một quy ước thiết kế của nhà cung cấp, trong trường hợp đó, SDK khách chỉ cập nhật giá trị chuyển đổi khi sự kiện đến tạo ra giá trị cao hơn trạng thái được ghi nhận hiện tại.
Lược đồ tự động có thể cập nhật các giá trị chuyển đổi nếu ứng dụng ngoại tuyến không?
Có. Nếu SDK có một lược đồ được lưu đệm hợp lệ, nó có thể đánh giá các sự kiện và gọi StoreKit mà không cần tìm nạp lược đồ mới một cách đồng bộ. Việc chuẩn bị và gửi bài đăng SKAdNetwork tiếp tục được hệ thống quản lý và diễn ra không đồng bộ.
Lược đồ tự động xử lý việc chuyển đổi tiền tệ cho người dùng toàn cầu như thế nào?
Một công cụ lược đồ tự động sẽ chuẩn hóa tất cả các khoản mua hàng trong ứng dụng thành một loại tiền tệ cơ sở tiêu chuẩn (chẳng hạn như xu USD) trên thiết bị hoặc chuyển các giá trị số nguyên đã chuyển đổi trước khi đánh giá các ngưỡng phân đoạn doanh thu.

Tóm tắt và Khung quyết định

Tự động hóa ánh xạ giá trị chuyển đổi SKAdNetwork giúp tách biệt việc thử nghiệm tăng trưởng khỏi các chu kỳ phát hành bản dựng di động. Bằng cách phân phối các lược đồ động từ một bảng điều khiển phân bổ tập trung và đánh giá chúng cục bộ bên trong SDK, các nhóm kỹ thuật có thể tinh chỉnh các phân đoạn doanh thu, tối ưu hóa các mốc phễu và cấu hình khóa cửa sổ tự động, cho phép các thay đổi quy tắc chuyển đổi được hỗ trợ có hiệu lực mà không cần gửi lại các tệp nhị phân ứng dụng lên App Store Connect.

Định tuyến liên kết sâu (deep link) cấp ứng dụng có thể hoạt động song song với các khung phân bổ bảo vệ quyền riêng tư của Apple như một lớp đo lường và hướng dẫn riêng biệt. Các nền tảng như OpoInstall cung cấp cơ sở hạ tầng cho việc định tuyến theo ngữ cảnh của bên thứ nhất và liên kết sâu trì hoãn (deferred deep linking), cho phép các nhóm giữ nguyên ý định của người dùng xuyên suốt các phễu chuyển đổi từ web sang ứng dụng.

Để tìm hiểu thêm về việc cấu hình các đường ống phân bổ và liên kết sâu tuân thủ quyền riêng tư, hãy xem lại tài liệu OpoInstall.

Tài liệu liên quan

  • Khái niệm: Lược đồ giá trị chuyển đổi, Ánh xạ lược đồ động, Phân đoạn doanh thu, Khóa cửa sổ, Tính đơn điệu

  • Công nghệ: Apple SKAdNetwork, Apple AdAttributionKit, Khung StoreKit, SDK di động OpoInstall

  • Tiêu chuẩn: Đặc tả JSON IETF RFC 8259

  • API: API StoreKit updatePostbackConversionValue, API AdAttributionKit Postback.updateConversionValue

Tài liệu chính thức

Share this article