Lấy flows & paywalls - iOS

Nội dung mà getFlow trả về
Flow BETA Được tạo trong Flow Builder — render nguyên bản trên thiết bị, không cần WebView
Paywall của Paywall Builder Toàn bộ nội dung Paywall Builder hiện có

Sau khi bạn đã thiết kế flow hoặc paywall trong Paywall Builder, bạn có thể hiển thị nó trong ứng dụng di động của mình. Bước đầu tiên là lấy flow hoặc paywall được liên kết với placement và cấu hình view tương ứng như mô tả bên dưới.

Muốn xem ví dụ thực tế về cách tích hợp Adapty SDK vào ứng dụng di động? Hãy xem ứng dụng mẫu của chúng tôi, minh họa toàn bộ quá trình thiết lập, bao gồm hiển thị paywall, thực hiện mua hàng và các chức năng cơ bản khác.

Trước khi bắt đầu
  1. Tạo sản phẩm của bạn trong Adapty Dashboard.
  2. Tạo flow/paywall và đưa sản phẩm vào đó trong Adapty Dashboard.
  3. Tạo placement và đưa flow/paywall vào đó trong Adapty Dashboard.
  4. Cài đặt Adapty SDK vào ứng dụng di động của bạn.

Tải flow/paywall

Nếu bạn đã thiết kế một flow hoặc paywall bằng Flow Builder hoặc Paywall Builder, bạn không cần lo lắng về việc render nó trong code ứng dụng mobile để hiển thị cho người dùng. Flow hoặc paywall đó đã bao gồm cả nội dung cần hiển thị lẫn cách hiển thị. Tuy nhiên, bạn vẫn cần lấy ID của nó thông qua placement, cấu hình view, rồi mới trình bày nó trong ứng dụng mobile của bạn. Tải flow hoặc paywall và cấu hình view của nó càng sớm càng tốt — lý tưởng là trước khi hiển thị. Ngay khi bạn tải cấu hình view, SDK bắt đầu tải và cache hình ảnh trong nền. Tải càng sớm, các hình ảnh có càng nhiều thời gian để hoàn tất. Đến khi bạn hiển thị flow hoặc paywall, cấu hình và hình ảnh của nó đã có thể được cache sẵn sàng.

Để lấy flow hoặc paywall, sử dụng phương thức getFlow:

Tham số:

Tham sốBắt buộcMô tả
placementIdbắt buộcĐịnh danh của Placement mong muốn. Đây là giá trị bạn đã chỉ định khi tạo placement trong Adapty Dashboard.
fetchPolicymặc định: .reloadRevalidatingCacheData

Theo mặc định, SDK sẽ cố tải dữ liệu từ máy chủ và trả về dữ liệu đã lưu trong cache nếu thất bại. Chúng tôi khuyên dùng tùy chọn này vì nó đảm bảo người dùng luôn nhận được dữ liệu mới nhất.

Tuy nhiên, nếu bạn cho rằng người dùng của mình thường gặp tình trạng kết nối internet không ổn định, hãy cân nhắc dùng .returnCacheDataElseLoad để trả về dữ liệu đã lưu trong cache nếu có. Trong trường hợp này, người dùng có thể không nhận được dữ liệu mới nhất tuyệt đối, nhưng sẽ trải nghiệm tốc độ tải nhanh hơn dù kết nối có kém đến đâu. Cache được cập nhật định kỳ, vì vậy việc sử dụng nó trong phiên làm việc để tránh các yêu cầu mạng là hoàn toàn an toàn.

Lưu ý rằng cache vẫn được giữ nguyên sau khi khởi động lại ứng dụng và chỉ bị xóa khi cài đặt lại ứng dụng hoặc thực hiện dọn dẹp thủ công.

Adapty SDK lưu trữ paywall cục bộ theo hai lớp: cache được cập nhật định kỳ như mô tả ở trên và paywall dự phòng. Chúng tôi cũng sử dụng CDN để tải paywall nhanh hơn và một máy chủ dự phòng độc lập trong trường hợp CDN không thể truy cập. Hệ thống này được thiết kế để đảm bảo bạn luôn nhận được phiên bản paywall mới nhất trong khi vẫn đảm bảo độ tin cậy ngay cả khi kết nối internet yếu.

loadTimeoutmặc định: 5 giây

Giá trị này giới hạn thời gian chờ cho phương thức này. Nếu hết thời gian chờ, dữ liệu đã lưu trong cache hoặc fallback cục bộ sẽ được trả về.

Lưu ý rằng trong một số trường hợp hiếm gặp, phương thức này có thể timeout muộn hơn một chút so với giá trị được chỉ định trong loadTimeout, vì thao tác này có thể bao gồm nhiều yêu cầu khác nhau ở bên dưới.

Tham số phản hồi:
Tham sốMô tả
FlowMột đối tượng AdaptyFlow chứa placement, các định danh (id, variationId), tên, Remote Config, và cờ hasViewConfiguration cho biết flow có bao gồm cấu hình giao diện hay không. Để lấy các sản phẩm thực tế phục vụ việc tải trước, giao diện tùy chỉnh, hoặc kiểm tra theo chương trình, hãy gọi getPaywallProducts(flow:).

Lấy cấu hình giao diện

Sau khi lấy flow hoặc paywall, hãy kiểm tra xem nó có bao gồm cấu hình giao diện hay không thông qua flow.hasViewConfiguration. Cờ này cho biết cách placement được thiết kế trong Adapty Dashboard:

  • true — placement được thiết kế trong Flow Builder (một flow) hoặc Paywall Builder (một paywall). Adapty sẽ tự động hiển thị giao diện cho bạn. Tiếp tục với các bước bên dưới để lấy cấu hình giao diện và hiển thị flow hoặc paywall.
  • false — placement là một paywall tùy chỉnh không có giao diện Builder. Sử dụng phương thức getFlowConfiguration để tải cấu hình view.

guard flow.hasViewConfiguration else {
    // handle as remote config paywall
    return
}

let flowConfiguration = try await AdaptyUI.getFlowConfiguration(forFlow: flow)

Các tham số:

Tham sốBắt buộcMô tả
forFlowbắt buộcMột đối tượng AdaptyFlow lấy được qua Adapty.getFlow.
locale

tùy chọn

mặc định: nil

Mã định danh của bản địa hóa paywall. Nhập dưới dạng mã ngôn ngữ với một hoặc hai subtag phân cách bằng - (ví dụ: en, pt-br). Xem Bản địa hóa và mã locale.
loadTimeoutmặc định: 5 giâyGiá trị này giới hạn thời gian chờ cho phương thức này. Nếu hết thời gian chờ, dữ liệu đã cache hoặc fallback cục bộ sẽ được trả về. Lưu ý rằng trong một số trường hợp hiếm gặp, phương thức này có thể timeout muộn hơn một chút so với giá trị được chỉ định trong loadTimeout, do thao tác có thể bao gồm nhiều request khác nhau bên dưới.
productstùy chọnCung cấp một mảng các đối tượng AdaptyPaywallProduct để tối ưu hóa thời điểm hiển thị sản phẩm trên màn hình. Nếu truyền nil, AdaptyUI sẽ tự động fetch các sản phẩm cần thiết.
systemRequestsHandlertùy chọnMột đối tượng tuân theo AdaptySystemRequestsHandler để xử lý các yêu cầu quyền hệ thống và đánh giá được kích hoạt bởi các hành động trong flow. Chỉ cần thiết nếu flow của bạn có các hành động như vậy.
assetsResolvertùy chọnMột dictionary [String: AdaptyCustomAsset] dùng để ghi đè hình ảnh và video trong flow/paywall. Xem Tùy chỉnh assets.
timerResolvertùy chọnMột đối tượng tuân theo AdaptyTimerResolver cung cấp ngày kết thúc cho các bộ đếm thời gian do nhà phát triển định nghĩa. Xem Thiết lập bộ đếm thời gian do nhà phát triển định nghĩa.
Sau khi tải xong, hiển thị flow/paywall.

Lấy flow hoặc paywall cho đối tượng mặc định để tải nhanh hơn

Thông thường, flow và paywall được tải gần như ngay lập tức, nên bạn không cần lo lắng về việc tăng tốc quá trình này. Tuy nhiên, trong trường hợp bạn có nhiều đối tượng và placement, và người dùng của bạn có kết nối internet yếu, việc tải flow hoặc paywall có thể mất nhiều thời gian hơn mong muốn. Trong những tình huống như vậy, bạn có thể muốn hiển thị một flow hoặc paywall mặc định để đảm bảo trải nghiệm người dùng mượt mà thay vì không hiển thị gì cả. Để giải quyết vấn đề này, bạn có thể dùng phương thức getFlowForDefaultAudience, phương thức này lấy flow hoặc paywall của placement được chỉ định cho đối tượng All Users. Tuy nhiên, điều quan trọng cần hiểu là cách tiếp cận được khuyến nghị là lấy flow hoặc paywall bằng phương thức getFlow, như đã trình bày trong phần Lấy thông tin Paywall ở trên.

Lý do chúng tôi khuyến nghị dùng getFlow

Phương thức getFlowForDefaultAudience có một số hạn chế đáng kể:

  • Vấn đề tương thích ngược tiềm ẩn: Nếu bạn cần hiển thị các paywall khác nhau cho các phiên bản ứng dụng khác nhau (hiện tại và tương lai), bạn có thể gặp khó khăn. Bạn sẽ phải thiết kế các paywall hỗ trợ phiên bản hiện tại (cũ) hoặc chấp nhận rằng người dùng với phiên bản hiện tại (cũ) có thể gặp sự cố với các paywall không được hiển thị.
  • Mất khả năng targeting: Tất cả người dùng sẽ thấy cùng một paywall được thiết kế cho đối tượng All Users, nghĩa là bạn mất đi khả năng targeting cá nhân hóa (bao gồm dựa trên quốc gia, attribution marketing hoặc các thuộc tính tùy chỉnh của riêng bạn). Nếu bạn chấp nhận những hạn chế này để đổi lấy tốc độ tải flow hoặc paywall nhanh hơn, hãy sử dụng phương thức getFlowForDefaultAudience như sau. Nếu không, hãy tiếp tục dùng getFlow đã được mô tả ở trên.
Adapty.getFlowForDefaultAudience(placementId: "YOUR_PLACEMENT_ID") { result in
    switch result {
        case let .success(flow):
            // the requested flow
        case let .failure(error):
            // handle the error
    }
}
Tham sốBắt buộcMô tả
placementIdbắt buộcMã định danh của Placement. Đây là giá trị bạn đã chỉ định khi tạo placement trong Adapty Dashboard.
fetchPolicymặc định: .reloadRevalidatingCacheData

Theo mặc định, SDK sẽ cố tải dữ liệu từ máy chủ và trả về dữ liệu đã cache nếu thất bại. Chúng tôi khuyến nghị dùng tùy chọn này vì nó đảm bảo người dùng luôn nhận được dữ liệu mới nhất.

Tuy nhiên, nếu bạn cho rằng người dùng của mình thường xuyên gặp tình trạng mạng không ổn định, hãy cân nhắc dùng .returnCacheDataElseLoad để trả về dữ liệu đã cache nếu có. Trong trường hợp này, người dùng có thể không nhận được dữ liệu mới nhất tuyệt đối, nhưng thời gian tải sẽ nhanh hơn bất kể kết nối mạng có yếu đến đâu. Cache được cập nhật thường xuyên nên hoàn toàn an toàn khi dùng trong phiên làm việc để tránh các yêu cầu mạng không cần thiết.

Lưu ý rằng cache vẫn được giữ nguyên khi khởi động lại ứng dụng và chỉ bị xóa khi gỡ cài đặt ứng dụng hoặc xóa thủ công.

Tùy chỉnh assets

Để tùy chỉnh hình ảnh và video trong paywall/flow của bạn, hãy triển khai custom assets.

Hình ảnh hero và video có ID được định sẵn: hero_imagehero_video. Trong một custom asset bundle, bạn nhắm đến các phần tử này theo ID của chúng và tùy chỉnh hành vi của chúng.

Đối với các hình ảnh và video khác, bạn cần đặt ID tùy chỉnh trong Adapty dashboard.

Ví dụ, bạn có thể:

  • Hiển thị hình ảnh hoặc video khác nhau cho một số người dùng.
  • Hiển thị hình ảnh xem trước cục bộ trong khi hình ảnh chính từ xa đang tải.
  • Hiển thị hình ảnh xem trước trước khi phát video.
  • Cung cấp độ phân giải pixel của video để trình phát có thể dành sẵn không gian bố cục (tỷ lệ khung hình = width / height) trước khi video tải. Truyền nil để bỏ qua phần này.

Dưới đây là ví dụ về cách cung cấp các asset tùy chỉnh thông qua một dictionary đơn giản:

let customAssets: [String: AdaptyCustomAsset] = [
    // Show a local image using a custom ID
    "custom_image": .image(
        .uiImage(value: UIImage(named: "image_name")!)
    ),

    // Show a local preview image while a remote main image is loading
    "hero_image": .image(
        .remote(
            url: URL(string: "https://example.com/image.jpg")!,
            preview: UIImage(named: "preview_image")
        )
    ),

    // Show a local video with a preview image and a known resolution
    "hero_video": .video(
        .file(
            url: Bundle.main.url(forResource: "custom_video", withExtension: "mp4")!,
            preview: .uiImage(value: UIImage(named: "video_preview")!),
            resolution: CGSize(width: 1080, height: 1920)
        )
    ),
]

let flowConfig = try await AdaptyUI.getFlowConfiguration(
    forFlow: flow,
    assetsResolver: customAssets
)

Nếu không tìm thấy asset, paywall/flow sẽ hiển thị theo giao diện mặc định.

Thiết lập timer do lập trình viên định nghĩa

Để sử dụng timer tùy chỉnh trong ứng dụng, hãy tạo một object tuân theo protocol AdaptyTimerResolver. Object này định nghĩa cách hiển thị từng timer tùy chỉnh. Nếu muốn, bạn có thể dùng trực tiếp dictionary [String: Date] vì nó đã tương thích với protocol này. Dưới đây là ví dụ:

@MainActor
struct AdaptyTimerResolverImpl: AdaptyTimerResolver {
    func timerEndAtDate(for timerId: String) -> Date {
        switch timerId {
        case "CUSTOM_TIMER_6H":
            Date(timeIntervalSinceNow: 3600.0 * 6.0) // 6 hours
        case "CUSTOM_TIMER_NY":
            Calendar.current.date(from: DateComponents(year: 2025, month: 1, day: 1)) ?? Date(timeIntervalSinceNow: 3600.0)
        default:
            Date(timeIntervalSinceNow: 3600.0) // 1 hour
        }
    }
}

Trong ví dụ này, CUSTOM_TIMER_NYCUSTOM_TIMER_6H là các Timer ID của các timer do developer tự định nghĩa mà bạn đã thiết lập trong Adapty Dashboard. timerResolver đảm bảo ứng dụng của bạn cập nhật động từng timer với giá trị chính xác. Ví dụ:

  • CUSTOM_TIMER_NY: Thời gian còn lại cho đến khi timer kết thúc, chẳng hạn như Năm Mới.
  • CUSTOM_TIMER_6H: Thời gian còn lại trong khoảng 6 giờ bắt đầu từ khi người dùng mở paywall.

Sau khi bạn đã thiết kế phần hiển thị cho paywall của mình bằng Paywall Builder trong Adapty Dashboard, bạn có thể hiển thị nó trong ứng dụng di động. Bước đầu tiên là lấy paywall liên kết với placement và cấu hình giao diện của nó như mô tả bên dưới.

Lưu ý rằng chủ đề này đề cập đến các paywall được tùy chỉnh bằng Paywall Builder. Nếu bạn đang triển khai paywall theo cách thủ công, hãy tham khảo Lấy paywall và sản phẩm cho paywall Remote Config.

Bạn muốn xem ví dụ thực tế về cách tích hợp Adapty SDK vào ứng dụng di động? Hãy xem ứng dụng mẫu của chúng tôi, bao gồm toàn bộ thiết lập, từ hiển thị paywall, thực hiện mua hàng đến các chức năng cơ bản khác.

Trước khi bắt đầu hiển thị paywall trong ứng dụng di động của bạn
  1. Tạo sản phẩm của bạn trong Adapty Dashboard.
  2. Tạo paywall và thêm sản phẩm vào đó trong Adapty Dashboard.
  3. Tạo placement và thêm paywall vào đó trong Adapty Dashboard.
  4. Cài đặt Adapty SDK vào ứng dụng di động của bạn.

Tải paywall được thiết kế bằng Paywall Builder

Nếu bạn đã thiết kế paywall bằng Paywall Builder, bạn không cần lo lắng về việc render nó trong code ứng dụng để hiển thị cho người dùng. Paywall như vậy đã bao gồm cả nội dung hiển thị lẫn cách thức hiển thị. Tuy nhiên, bạn vẫn cần lấy ID của nó thông qua placement, cấu hình view, rồi mới trình bày nó trong ứng dụng. Để đảm bảo hiệu suất tối ưu, hãy lấy paywall và cấu hình hiển thị của nó càng sớm càng tốt, nhờ đó ảnh có đủ thời gian tải xuống trước khi hiển thị cho người dùng.

Để lấy paywall, sử dụng phương thức getPaywall:

Tham số:

Tham sốBắt buộcMô tả
placementIdbắt buộcMã định danh của Placement mong muốn. Đây là giá trị bạn đã chỉ định khi tạo placement trong Adapty Dashboard.
locale

tùy chọn

mặc định: en

Mã định danh của bản dịch paywall. Tham số này được kỳ vọng là mã ngôn ngữ gồm một hoặc hai thẻ con được phân cách bằng ký tự gạch ngang (-). Thẻ con đầu tiên là ngôn ngữ, thẻ con thứ hai là khu vực.

Ví dụ: en là tiếng Anh, pt-br là tiếng Bồ Đào Nha (Brazil).

Xem Bản dịch và mã locale để biết thêm thông tin về mã locale và cách chúng tôi khuyến nghị sử dụng chúng.

fetchPolicymặc định: .reloadRevalidatingCacheData

Theo mặc định, SDK sẽ cố tải dữ liệu từ máy chủ và trả về dữ liệu đã cache nếu thất bại. Chúng tôi khuyến nghị cách này vì nó đảm bảo người dùng luôn nhận được dữ liệu mới nhất.

Tuy nhiên, nếu bạn cho rằng người dùng của mình thường xuyên gặp tình trạng mạng không ổn định, hãy cân nhắc dùng .returnCacheDataElseLoad để trả về dữ liệu đã cache nếu có. Trong trường hợp này, người dùng có thể không nhận được dữ liệu mới nhất tuyệt đối, nhưng sẽ tải nhanh hơn bất kể kết nối mạng có chập chờn đến đâu. Cache được cập nhật thường xuyên, nên hoàn toàn an toàn khi dùng trong phiên làm việc để tránh các yêu cầu mạng.

Lưu ý rằng cache vẫn được giữ nguyên khi khởi động lại ứng dụng và chỉ bị xóa khi gỡ cài đặt ứng dụng hoặc thực hiện dọn dẹp thủ công.

Adapty SDK lưu trữ paywall cục bộ theo hai lớp: cache được cập nhật thường xuyên như mô tả ở trên và paywall dự phòng. Chúng tôi cũng sử dụng CDN để tải paywall nhanh hơn và một máy chủ dự phòng độc lập trong trường hợp CDN không thể truy cập. Hệ thống này được thiết kế để đảm bảo bạn luôn nhận được phiên bản mới nhất của paywall, đồng thời đảm bảo độ tin cậy ngay cả khi kết nối mạng yếu.

loadTimeoutmặc định: 5 giây

Giá trị này giới hạn thời gian chờ cho phương thức này. Nếu hết thời gian chờ, dữ liệu đã cache hoặc fallback cục bộ sẽ được trả về.

Lưu ý rằng trong một số trường hợp hiếm gặp, phương thức này có thể hết thời gian chờ trễ hơn một chút so với giá trị đã chỉ định trong loadTimeout, do thao tác này có thể bao gồm nhiều yêu cầu khác nhau bên dưới.

Tham số phản hồi:
Tham sốMô tả
PaywallĐối tượng AdaptyPaywall chứa danh sách ID sản phẩm, định danh paywall, Remote Config và một số thuộc tính khác.

Lấy cấu hình hiển thị của paywall được thiết kế bằng Paywall Builder

Hãy đảm bảo bật toggle Show on device trong Paywall Builder. Nếu tùy chọn này chưa được bật, cấu hình hiển thị sẽ không thể lấy được.

Sau khi lấy paywall, hãy kiểm tra xem nó có chứa cấu hình hiển thị hay không — đây là dấu hiệu cho thấy paywall được tạo bằng Paywall Builder. Điều này sẽ giúp bạn biết cách hiển thị paywall. Nếu cấu hình hiển thị có mặt, hãy xử lý nó như một paywall Paywall Builder; nếu không, xử lý nó như một paywall Remote Config. Sử dụng phương thức getPaywallConfiguration để tải cấu hình view.


guard paywall.hasViewConfiguration else {
    //  use your custom logic
    return
}

do {
    let paywallConfiguration = try await AdaptyUI.getPaywallConfiguration(
            forPaywall: paywall,
            products: products
    )
    // use loaded configuration
} catch {
    // handle the error
}

Tham số:

Tham sốBắt buộcMô tả
paywallbắt buộcĐối tượng AdaptyPaywall để lấy controller cho paywall mong muốn.
loadTimeoutmặc định: 5 giâyGiá trị này giới hạn timeout cho phương thức này. Nếu hết thời gian chờ, dữ liệu được cache hoặc fallback cục bộ sẽ được trả về. Lưu ý rằng trong một số trường hợp hiếm gặp, phương thức này có thể timeout muộn hơn một chút so với giá trị được chỉ định trong loadTimeout, vì thao tác có thể bao gồm nhiều request khác nhau bên dưới.
productstùy chọnCung cấp một mảng các đối tượng AdaptyPaywallProduct để tối ưu hóa thời điểm hiển thị sản phẩm trên màn hình. Nếu truyền vào nil, AdaptyUI sẽ tự động tải các sản phẩm cần thiết.

Nếu bạn đang sử dụng nhiều ngôn ngữ, hãy tìm hiểu cách thêm bản địa hóa Paywall Builder và cách sử dụng mã locale đúng cách tại đây.

Sau khi tải xong, hãy hiển thị paywall.

Lấy paywall cho đối tượng mặc định để tải nhanh hơn

Thông thường, paywall được tải gần như ngay lập tức, nên bạn không cần lo lắng về việc tối ưu tốc độ. Tuy nhiên, trong trường hợp bạn có nhiều đối tượng và paywall, hoặc người dùng đang dùng kết nối internet yếu, việc tải paywall có thể mất nhiều thời gian hơn mong muốn. Trong những tình huống đó, bạn có thể muốn hiển thị paywall mặc định để đảm bảo trải nghiệm người dùng mượt mà thay vì không hiển thị paywall nào cả. Để giải quyết vấn đề này, bạn có thể sử dụng phương thức getPaywallForDefaultAudience, phương thức này sẽ lấy paywall của placement đã chỉ định cho đối tượng All Users. Tuy nhiên, điều quan trọng cần hiểu là phương pháp được khuyến nghị vẫn là lấy paywall qua phương thức getPaywall, như đã trình bày chi tiết trong phần Lấy thông tin Paywall ở trên.

Lý do chúng tôi khuyến nghị sử dụng getPaywall

Phương thức getPaywallForDefaultAudience có một số hạn chế đáng kể:

  • Vấn đề tương thích ngược: Nếu bạn cần hiển thị các paywall khác nhau cho các phiên bản ứng dụng khác nhau (phiên bản hiện tại và tương lai), bạn có thể gặp khó khăn. Bạn sẽ phải thiết kế các paywall hỗ trợ phiên bản hiện tại (cũ) hoặc chấp nhận rằng người dùng với phiên bản hiện tại (cũ) có thể gặp sự cố với các paywall không hiển thị được.
  • Mất khả năng nhắm mục tiêu: Tất cả người dùng sẽ thấy cùng một paywall được thiết kế cho đối tượng All Users, nghĩa là bạn mất đi khả năng cá nhân hóa mục tiêu (bao gồm theo quốc gia, attribution marketing hoặc các thuộc tính tùy chỉnh của riêng bạn). Nếu bạn sẵn sàng chấp nhận những hạn chế này để có được tốc độ tải paywall nhanh hơn, hãy sử dụng phương thức getPaywallForDefaultAudience như sau. Nếu không, hãy dùng getPaywall đã được mô tả ở trên.
Adapty.getPaywallForDefaultAudience(placementId: "YOUR_PLACEMENT_ID", locale: "en") { result in
    switch result {
        case let .success(paywall):
            // the requested paywall
        case let .failure(error):
            // handle the error
    }
}

Phương thức getPaywallForDefaultAudience khả dụng từ iOS SDK phiên bản 2.11.2 trở lên.

Tham sốBắt buộcMô tả
placementIdbắt buộcMã định danh của Placement. Đây là giá trị bạn đã chỉ định khi tạo placement trong Adapty Dashboard.
locale

tùy chọn

mặc định: en

Mã định danh của bản dịch paywall. Tham số này là mã ngôn ngữ gồm một hoặc nhiều thẻ con phân cách bằng ký tự dấu trừ (-). Thẻ con đầu tiên là ngôn ngữ, thẻ con thứ hai là vùng.

Ví dụ: en là tiếng Anh, pt-br là tiếng Bồ Đào Nha (Brazil).

Xem Localizations và mã locale để biết thêm thông tin về mã locale và cách chúng tôi khuyến nghị sử dụng.

fetchPolicymặc định: .reloadRevalidatingCacheData

Theo mặc định, SDK sẽ cố tải dữ liệu từ máy chủ và trả về dữ liệu đã lưu trong bộ nhớ đệm nếu thất bại. Chúng tôi khuyến nghị lựa chọn này vì nó đảm bảo người dùng luôn nhận được dữ liệu mới nhất.

Tuy nhiên, nếu bạn cho rằng người dùng của mình thường xuyên gặp tình trạng kết nối không ổn định, hãy cân nhắc dùng .returnCacheDataElseLoad để trả về dữ liệu từ bộ nhớ đệm nếu có. Trong trường hợp này, người dùng có thể không nhận được dữ liệu mới nhất tuyệt đối, nhưng thời gian tải sẽ nhanh hơn dù kết nối internet kém đến đâu. Bộ nhớ đệm được cập nhật thường xuyên, nên hoàn toàn an toàn khi sử dụng trong phiên làm việc để tránh các yêu cầu mạng.

Lưu ý rằng bộ nhớ đệm vẫn tồn tại sau khi khởi động lại ứng dụng và chỉ bị xóa khi cài đặt lại ứng dụng hoặc xóa thủ công.

Tùy chỉnh assets

Để tùy chỉnh hình ảnh và video trong paywall của bạn, hãy triển khai custom assets.

Hero image và video có ID được định sẵn: hero_imagehero_video. Trong một custom asset bundle, bạn nhắm tới các phần tử này bằng ID của chúng và tùy chỉnh hành vi của chúng.

Đối với các hình ảnh và video khác, bạn cần đặt ID tùy chỉnh trong Adapty dashboard.

Ví dụ, bạn có thể:

  • Hiển thị hình ảnh hoặc video khác cho một số người dùng.
  • Hiển thị ảnh xem trước cục bộ trong khi hình ảnh chính từ xa đang tải.
  • Hiển thị ảnh xem trước trước khi phát video.

Để sử dụng tính năng này, hãy cập nhật Adapty iOS SDK lên phiên bản 3.7.0 trở lên.

Đây là ví dụ về cách bạn có thể cung cấp custom assets thông qua một dictionary đơn giản:

let customAssets: [String: AdaptyCustomAsset] = [
    // Show a local image using a custom ID
    "custom_image": .image(
        .uiImage(value: UIImage(named: "image_name")!)
    ),

    // Show a local preview image while a remote main image is loading
    "hero_image": .image(
        .remote(
            url: URL(string: "https://example.com/image.jpg")!,
            preview: UIImage(named: "preview_image")
        )
    ),

    // Show a local video with a preview image
    "hero_video": .video(
        .file(
            url: Bundle.main.url(forResource: "custom_video", withExtension: "mp4")!,
            preview: .uiImage(value: UIImage(named: "video_preview")!)
        )
    ),
]

let paywallConfig = try await AdaptyUI.getPaywallConfiguration(
    forPaywall: paywall,
    assetsResolver: customAssets
)

Nếu không tìm thấy asset, paywall sẽ trở về giao diện mặc định.

Thiết lập timer do developer định nghĩa

Để sử dụng custom timer trong ứng dụng mobile, hãy tạo một object tuân theo protocol AdaptyTimerResolver. Object này xác định cách mỗi custom timer sẽ được hiển thị. Nếu muốn, bạn có thể dùng trực tiếp dictionary [String: Date], vì nó đã tuân thủ protocol này. Dưới đây là ví dụ:

@MainActor
struct AdaptyTimerResolverImpl: AdaptyTimerResolver {
    func timerEndAtDate(for timerId: String) -> Date {
        switch timerId {
        case "CUSTOM_TIMER_6H":
            Date(timeIntervalSinceNow: 3600.0 * 6.0) // 6 hours
        case "CUSTOM_TIMER_NY":
            Calendar.current.date(from: DateComponents(year: 2025, month: 1, day: 1)) ?? Date(timeIntervalSinceNow: 3600.0)
        default:
            Date(timeIntervalSinceNow: 3600.0) // 1 hour
        }
    }
}

Trong ví dụ này, CUSTOM_TIMER_NYCUSTOM_TIMER_6HTimer ID của các timer do developer tự định nghĩa, được thiết lập trong Adapty Dashboard. timerResolver đảm bảo ứng dụng của bạn cập nhật động từng timer với giá trị chính xác. Ví dụ:

  • CUSTOM_TIMER_NY: Thời gian còn lại cho đến khi timer kết thúc, chẳng hạn như ngày Tết Dương lịch.
  • CUSTOM_TIMER_6H: Thời gian còn lại trong khoảng 6 giờ bắt đầu từ khi người dùng mở paywall.