Bật tính năng mua hàng với Flow Builder trong iOS SDK
Để bật tính năng in-app purchase, bạn cần hiểu ba khái niệm chính:
Sản phẩm – bất cứ thứ gì người dùng có thể mua (gói đăng ký, consumable, quyền truy cập trọn đời)
Flow – chuỗi màn hình giới thiệu sản phẩm đến người dùng, được xây dựng trong Flow Builder no-code. SDK lấy chúng qua getFlow. Nếu bạn muốn tự xây dựng giao diện trong code, hãy dùng paywall thay thế — xem Triển khai paywall thủ công.
Placement – vị trí và thời điểm bạn hiển thị flow trong app (ví dụ: main, onboarding, settings). Bạn gắn flow vào placement trong dashboard, sau đó lấy chúng theo placement ID trong code. Cách này giúp dễ dàng chạy A/B test và hiển thị các flow khác nhau cho từng nhóm người dùng.
Adapty cung cấp ba cách để bật tính năng mua hàng trong app. Chọn một trong số đó tùy theo yêu cầu của app bạn:
Bạn tự triển khai giao diện paywall trong code app, nhưng vẫn lấy đối tượng flow từ Adapty để linh hoạt trong việc cung cấp sản phẩm. Xem hướng dẫn.
Observer mode
🔴 Khó
Bạn đã có sẵn hệ thống xử lý mua hàng riêng và muốn tiếp tục sử dụng nó. Lưu ý rằng observer mode có những hạn chế nhất định trong Adapty. Xem bài viết.
Các bước dưới đây hướng dẫn cách triển khai một flow được tạo trong Adapty Flow Builder.
Để hiển thị một flow được tạo trong Adapty Flow Builder, trong code app của bạn, bạn chỉ cần:
Lấy flow: Lấy từ Adapty.
Hiển thị và Adapty sẽ xử lý mua hàng cho bạn: Hiển thị view trong app.
Xử lý hành động nút bấm: Liên kết tương tác của người dùng với phản hồi tương ứng trong app. Ví dụ: mở liên kết hoặc đóng flow khi người dùng nhấn nút.
Các flow của bạn được liên kết với các placement được cấu hình trong dashboard. Placement cho phép bạn chạy các flow khác nhau cho các đối tượng khác nhau hoặc để chạy A/B test.
Để lấy một flow được tạo trong Adapty Flow Builder, bạn cần:
Lấy đối tượng flow theo placement ID bằng phương thức getFlow và kiểm tra xem nó có cấu hình view hay không.
Lấy cấu hình view bằng phương thức getFlowConfiguration. Nó chứa các phần tử giao diện và style cần thiết để hiển thị flow.
func loadFlow() async { let flow = try await Adapty.getFlow(placementId: "YOUR_PLACEMENT_ID") guard flow.hasViewConfiguration else { print("Flow doesn't have a view configuration") return } flowConfiguration = try await AdaptyUI.getFlowConfiguration(forFlow: flow)}
2. Hiển thị flow
Sau khi có cấu hình flow, bạn chỉ cần thêm vài dòng code để hiển thị flow.
Trong SwiftUI, khi hiển thị flow, bạn cũng cần xử lý các sự kiện. didFailPurchase, didFinishRestore, didFailRestore, và didReceiveError là bắt buộc. Khi kiểm thử, bạn có thể chỉ cần sao chép code từ đoạn snippet dưới đây để ghi log các sự kiện này.
Xử lý didFinishPurchase không bắt buộc, nhưng hữu ích khi bạn muốn thực hiện hành động sau khi mua hàng thành công. Nếu bạn không triển khai callback đó, flow sẽ tự động đóng lại.
Triển khai AdaptyFlowControllerDelegate để xử lý các sự kiện. Tối thiểu, hãy triển khai các error handler bắt buộc (ba phương thức không có implementation mặc định):
Để biết thêm chi tiết về cách hiển thị flow, xem hướng dẫn của chúng tôi.
3. Xử lý hành động nút bấm
Khi người dùng nhấn nút, iOS SDK tự động xử lý việc mua hàng, khôi phục, đóng flow và mở liên kết.
Tuy nhiên, các nút khác có ID tùy chỉnh hoặc được định nghĩa trước và yêu cầu xử lý hành động trong code của bạn. Hoặc bạn có thể muốn ghi đè hành vi mặc định của chúng.
Ví dụ, đây là cách xử lý nút đóng. Trong UIKit, SDK tự động đóng controller khi .close được kích hoạt — chỉ ghi đè nếu bạn muốn hành vi tùy chỉnh. Trong SwiftUI, bạn phải tự đặt binding isPresented thành false.
Đọc các hướng dẫn của chúng tôi về cách xử lý hành động và sự kiện của nút bấm.
.flow( isPresented: $flowPresented, flowConfiguration: flowConfiguration, didPerformAction: { action in switch action { case .close: flowPresented = false // dismiss the flow when the user taps close default: break } }, didFailPurchase: { product, error in /* handle the error */ }, didFinishRestore: { profile in /* check access level and dismiss */ }, didFailRestore: { error in /* handle the error */ }, didReceiveError: { error in flowPresented = false })
Bạn có câu hỏi hoặc gặp sự cố? Hãy xem diễn đàn hỗ trợ của chúng tôi — nơi bạn có thể tìm câu trả lời cho các câu hỏi thường gặp hoặc đặt câu hỏi của riêng mình. Đội ngũ và cộng đồng của chúng tôi luôn sẵn sàng giúp đỡ!
Tiếp theo, bạn cần kiểm tra mức độ truy cập của người dùng để đảm bảo bạn hiển thị flow hoặc cấp quyền truy cập vào các tính năng trả phí cho đúng người dùng.
Ví dụ đầy đủ
Đây là cách tất cả các bước trong hướng dẫn này có thể được tích hợp vào app của bạn cùng nhau.
struct ContentView: View { @State private var flowPresented = false @State private var flowConfiguration: AdaptyUI.FlowConfiguration? @State private var isLoading = false @State private var hasInitialized = false var body: some View { VStack { if isLoading { ProgressView("Loading...") } else { Text("Your App Content") } } .task { guard !hasInitialized else { return } await initializeFlow() hasInitialized = true } .flow( isPresented: $flowPresented, flowConfiguration: flowConfiguration, didPerformAction: { action in switch action { case .close: flowPresented = false default: break } }, didFailPurchase: { product, error in print("Purchase failed: \(error)") }, didFinishRestore: { profile in print("Restore finished successfully") }, didFailRestore: { error in print("Restore failed: \(error)") }, didReceiveError: { error in print("Flow error: \(error)") flowPresented = false } ) } private func initializeFlow() async { isLoading = true defer { isLoading = false } await loadFlow() flowPresented = true } private func loadFlow() async { do { let flow = try await Adapty.getFlow(placementId: "YOUR_PLACEMENT_ID") guard flow.hasViewConfiguration else { print("Flow doesn't have a view configuration") return } flowConfiguration = try await AdaptyUI.getFlowConfiguration(forFlow: flow) } catch { print("Failed to load: \(error)") } }}