Flutter - Xử lý sự kiện flow & paywall
Hướng dẫn này đề cập đến việc xử lý sự kiện cho các giao dịch mua, khôi phục, lựa chọn sản phẩm và hiển thị. Việc đóng view và mở liên kết được xử lý bởi implementation mặc định của flowViewDidPerformAction — xem hướng dẫn xử lý hành động button để ghi đè chúng hoặc xử lý các hành động button tùy chỉnh.
Flows và paywalls được cấu hình bằng builder không cần thêm code để thực hiện và khôi phục giao dịch mua. Tuy nhiên, chúng tạo ra một số sự kiện mà ứng dụng của bạn có thể phản hồi. Những sự kiện này bao gồm các lần nhấn nút (nút đóng, URL, lựa chọn sản phẩm, v.v.) cũng như thông báo về các hành động liên quan đến giao dịch mua diễn ra trên flow hoặc paywall. Tìm hiểu cách phản hồi các sự kiện này bên dưới.
Để kiểm soát hoặc theo dõi các tiến trình xảy ra trên màn hình flow hoặc paywall trong ứng dụng di động của bạn, hãy triển khai các phương thức AdaptyUIFlowsEventsObserver và thiết lập observer trước khi hiển thị bất kỳ màn hình nào:
AdaptyUI().setFlowsEventsObserver(this);Ba phương thức observer là bắt buộc — class của bạn sẽ không biên dịch được nếu thiếu chúng: flowViewDidFinishPurchase, flowViewDidFinishRestore, và flowViewDidReceiveError. Tất cả các phương thức còn lại là tùy chọn. Để hủy kết nối một observer đã được thiết lập trước đó, truyền null vào setFlowsEventsObserver.
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, nơ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.
Các ví dụ sự kiện dưới đây hiển thị các thuộc tính có sẵn trên từng đối tượng, với các giá trị minh họa trong phần chú thích.
Sự kiện do người dùng tạo ra
View appeared
Phương thức này được gọi khi flow hoặc màn hình paywall xuất hiện trên màn hình.
Trên iOS, phương thức này cũng được gọi khi người dùng nhấn vào nút web paywall bên trong một paywall, và web paywall mở ra trong trình duyệt trong ứng dụng.
void flowViewDidAppear(AdaptyUIFlowView view) {
}View disappeared
Phương thức này được gọi khi flow hoặc màn hình paywall bị đóng khỏi màn hình.
Trên iOS, cũng được gọi khi một web paywall mở từ paywall trong trình duyệt trong ứng dụng biến mất khỏi màn hình.
void flowViewDidDisappear(AdaptyUIFlowView view) {
}Chọn sản phẩm
Nếu một sản phẩm được chọn để mua (bởi người dùng hoặc hệ thống), phương thức này sẽ được gọi:
void flowViewDidSelectProduct(AdaptyUIFlowView view, String productId) {
}Ví dụ sự kiện (Nhấn để mở rộng)
void flowViewDidSelectProduct(AdaptyUIFlowView view, String productId) {
// productId is a String:
productId; // 'premium_monthly'
}Đã bắt đầu mua hàng
Nếu người dùng bắt đầu quá trình mua hàng, phương thức này sẽ được gọi:
void flowViewDidStartPurchase(AdaptyUIFlowView view, AdaptyPaywallProduct product) {
}Ví dụ sự kiện (Nhấn để mở rộng)
void flowViewDidStartPurchase(AdaptyUIFlowView view, AdaptyPaywallProduct product) {
// product — AdaptyPaywallProduct:
product.vendorProductId; // 'premium_monthly'
product.localizedTitle; // 'Premium Monthly'
product.localizedDescription; // 'Premium subscription for 1 month'
product.price.amount; // 9.99 (double)
product.price.currencyCode; // 'USD'
product.price.localizedString; // '$9.99'
}Hoàn tất giao dịch mua
Phương thức này là bắt buộc. Nó được gọi khi một giao dịch mua thành công, người dùng hủy giao dịch, hoặc giao dịch có vẻ đang chờ xử lý:
void flowViewDidFinishPurchase(AdaptyUIFlowView view,
AdaptyPaywallProduct product,
AdaptyPurchaseResult purchaseResult) {
switch (purchaseResult) {
case AdaptyPurchaseResultSuccess(profile: final profile):
// successful purchase
break;
case AdaptyPurchaseResultPending():
// purchase is pending
break;
case AdaptyPurchaseResultUserCancelled():
// user cancelled the purchase
break;
default:
break;
}
}Ví dụ sự kiện (Nhấn để mở rộng)
void flowViewDidFinishPurchase(AdaptyUIFlowView view,
AdaptyPaywallProduct product,
AdaptyPurchaseResult purchaseResult) {
// product — AdaptyPaywallProduct:
product.vendorProductId; // 'premium_monthly'
switch (purchaseResult) {
case AdaptyPurchaseResultSuccess(profile: final profile):
// profile — AdaptyProfile:
profile.accessLevels['premium']?.isActive; // true
profile.accessLevels['premium']?.expiresAt; // DateTime(2027, 2, 15, 10, 30)
break;
case AdaptyPurchaseResultPending():
// no additional data
break;
case AdaptyPurchaseResultUserCancelled():
// no additional data
break;
}
}Khác với v3, phương thức này không có hành vi mặc định — view sẽ không tự động bị đóng sau khi mua thành công. Bạn tự quyết định bước tiếp theo: tiếp tục flow hoặc gọi view.dismiss(). Tham khảo Xử lý hành động nút để biết thêm chi tiết về cách đóng màn hình.
Hoàn tất điều hướng thanh toán web
Phương thức này được gọi sau khi có một lần thử mở web paywall cho một sản phẩm cụ thể. Điều này bao gồm cả các lần điều hướng thành công lẫn thất bại:
void flowViewDidFinishWebPaymentNavigation(AdaptyUIFlowView view,
AdaptyPaywallProduct? product,
AdaptyError? error) {
}Tham số:
| Tham số | Mô tả |
|---|---|
| product | Một AdaptyPaywallProduct mà web paywall đã được mở. Có thể là null. |
| error | Một đối tượng AdaptyError nếu điều hướng web paywall thất bại; null nếu điều hướng thành công. |
Giao dịch thất bại
Phương thức này được gọi khi một giao dịch mua thất bại (ví dụ: do sự cố thanh toán hoặc lỗi mạng). Nó không kích hoạt khi người dùng tự hủy hoặc khi giao dịch đang chờ xử lý—những trường hợp đó được xử lý bởi flowViewDidFinishPurchase:
void flowViewDidFailPurchase(AdaptyUIFlowView view,
AdaptyPaywallProduct product,
AdaptyError error) {
}Bắt đầu khôi phục
Nếu người dùng bắt đầu quá trình khôi phục, phương thức này sẽ được gọi:
void flowViewDidStartRestore(AdaptyUIFlowView view) {
}Khôi phục thành công
Phương thức này là bắt buộc. Nếu việc khôi phục mua hàng thành công, nó sẽ được gọi:
void flowViewDidFinishRestore(AdaptyUIFlowView view, AdaptyProfile profile) {
}Ví dụ sự kiện (Nhấn để mở rộng)
void flowViewDidFinishRestore(AdaptyUIFlowView view, AdaptyProfile profile) {
// profile — AdaptyProfile:
profile.accessLevels['premium']?.isActive; // true
profile.accessLevels['premium']?.expiresAt; // DateTime(2027, 2, 15, 10, 30)
profile.subscriptions['premium_monthly']?.isActive; // true
profile.subscriptions['premium_monthly']?.expiresAt; // DateTime(2027, 2, 15, 10, 30)
}Chúng tôi khuyến nghị đóng màn hình nếu người dùng đã có accessLevel yêu cầu. Tham khảo chủ đề Trạng thái gói đăng ký để tìm hiểu cách kiểm tra và chủ đề Phản hồi các hành động nút để tìm hiểu cách đóng màn hình.
Khôi phục thất bại
Nếu việc khôi phục giao dịch mua thất bại, phương thức này sẽ được gọi:
void flowViewDidFailRestore(AdaptyUIFlowView view, AdaptyError error) {
}Tải dữ liệu và hiển thị
Lỗi tải sản phẩm
Nếu bạn không truyền mảng sản phẩm trong quá trình khởi tạo, AdaptyUI sẽ tự động lấy các đối tượng cần thiết từ máy chủ. Nếu thao tác này thất bại, AdaptyUI sẽ báo lỗi bằng cách gọi phương thức sau:
void flowViewDidFailLoadingProducts(AdaptyUIFlowView view, AdaptyError error) {
}Lỗi view
Phương thức này là bắt buộc. Nó thay thế phương thức paywallViewDidFailRendering của v3: các lỗi xảy ra trong quá trình render giao diện, cũng như các lỗi view khác, sẽ được báo cáo thông qua lần gọi này. Sau khi bạn implement nó, việc đóng view là tùy bạn quyết định — chúng tôi khuyến nghị đóng view khi gặp các lỗi như vậy, đây cũng chính là hành vi mặc định tích hợp sẵn của SDK khi không có observer nào được thiết lập:
void flowViewDidReceiveError(AdaptyUIFlowView view, AdaptyError error) {
// log the error and dismiss the broken view
view.dismiss();
}Trong trường hợp bình thường, lỗi hiển thị không nên xảy ra, vì vậy nếu bạn gặp phải, hãy cho chúng tôi biết.
Sự kiện phân tích
Phương thức tùy chọn flowViewDidReceiveAnalyticEvent được dành riêng cho các sự kiện phân tích tùy chỉnh từ một flow. Hiện tại, các flow chưa phát các sự kiện này đến code của bạn, vì vậy bạn chưa cần triển khai nó.
Xử lý giao dịch mua hàng trong Observer mode
Nếu bạn đã kích hoạt SDK ở chế độ Observer mode và hiển thị một flow hoặc paywall do Adapty render, SDK sẽ không thực hiện giao dịch mua hàng thay bạn. Khi người dùng nhấn nút mua hàng hoặc khôi phục, SDK sẽ gọi AdaptyUIObserverModeResolver của bạn. Xem Hiển thị flow trong Observer mode để biết cách thiết lập đầy đủ.
Xử lý các yêu cầu hệ thống
AdaptyUISystemRequestsHandler (đăng ký qua AdaptyUI().setSystemRequestsHandler(...)) được dành riêng cho các yêu cầu hệ thống từ một flow: các lời nhắc cấp quyền của hệ điều hành (như thông báo đẩy hoặc quyền truy cập camera) và yêu cầu đánh giá trên App Store. Hiện tại các flow chưa kích hoạt những yêu cầu này, nên bạn chưa cần đăng ký handler.
Nếu bạn có đăng ký một cái, hãy lưu ý rằng handlePermission là phương thức bắt buộc của class — hãy yêu cầu quyền bằng code của riêng bạn, sau đó trả về AdaptyUIPermissionResult.granted() hoặc AdaptyUIPermissionResult.denied(); còn handleAppReviewRequest là tùy chọn.
Hướng dẫn này đề cập đến việc xử lý sự kiện cho các giao dịch mua, khôi phục, chọn sản phẩm và hiển thị paywall. Bạn cũng cần triển khai xử lý nút (đóng paywall, mở liên kết, v.v.). Xem hướng dẫn xử lý hành động nút để biết thêm chi tiết.
Các paywall được cấu hình bằng Paywall Builder không cần thêm code để thực hiện và khôi phục giao dịch mua. Tuy nhiên, chúng tạo ra một số sự kiện mà ứng dụng của bạn có thể phản hồi. Các sự kiện đó bao gồm các lần nhấn nút (nút đóng, URL, chọn sản phẩm, v.v.) cũng như thông báo về các hành động liên quan đến giao dịch mua được thực hiện trên paywall. Hãy xem cách phản hồi các sự kiện này bên dưới.
Hướng dẫn này chỉ dành cho paywall Paywall Builder mới yêu cầu Adapty SDK v3.0 trở lên.
Để kiểm soát hoặc theo dõi các sự kiện xảy ra trên màn hình paywall trong ứng dụng di động của bạn, hãy implement các phương thức AdaptyUIPaywallsEventsObserver và đặt observer trước khi hiển thị bất kỳ màn hình nào:
AdaptyUI().setPaywallsEventsObserver(this);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, nơ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.
Các ví dụ về sự kiện bên dưới hiển thị các thuộc tính có sẵn trên mỗi đối tượng, cùng với các giá trị minh họa trong phần chú thích.
Sự kiện do người dùng tạo ra
Paywall xuất hiện
Phương thức này được gọi khi màn hình paywall hiển thị trên màn hình.
Trên iOS, cũng được gọi khi người dùng nhấn nút web paywall bên trong một paywall, và web paywall mở ra trong trình duyệt trong ứng dụng.
void paywallViewDidAppear(AdaptyUIPaywallView view) {
}Paywall biến mất
Phương thức này được gọi khi màn hình paywall bị đóng khỏi màn hình.
Trên iOS, cũng được gọi khi một web paywall mở từ một paywall trong trình duyệt trong ứng dụng biến mất khỏi màn hình.
void paywallViewDidDisappear(AdaptyUIPaywallView view) {
}Chọn sản phẩm
Nếu một sản phẩm được chọn để mua (bởi người dùng hoặc bởi hệ thống), phương thức này sẽ được gọi:
void paywallViewDidSelectProduct(AdaptyUIPaywallView view, String productId) {
}Ví dụ sự kiện (Nhấn để mở rộng)
void paywallViewDidSelectProduct(AdaptyUIPaywallView view, String productId) {
// productId is a String:
productId; // 'premium_monthly'
}Bắt đầu mua hàng
Khi người dùng bắt đầu quá trình mua hàng, phương thức này sẽ được gọi:
void paywallViewDidStartPurchase(AdaptyUIPaywallView view, AdaptyPaywallProduct product) {
}Ví dụ sự kiện (Nhấn để mở rộng)
void paywallViewDidStartPurchase(AdaptyUIPaywallView view, AdaptyPaywallProduct product) {
// product — AdaptyPaywallProduct:
product.vendorProductId; // 'premium_monthly'
product.localizedTitle; // 'Premium Monthly'
product.localizedDescription; // 'Premium subscription for 1 month'
product.price.amount; // 9.99 (double)
product.price.currencyCode; // 'USD'
product.price.localizedString; // '$9.99'
}Hoàn tất thanh toán
Phương thức này được gọi khi giao dịch mua thành công, người dùng hủy giao dịch, hoặc giao dịch đang ở trạng thái chờ xử lý:
void paywallViewDidFinishPurchase(AdaptyUIPaywallView view,
AdaptyPaywallProduct product,
AdaptyPurchaseResult purchaseResult) {
switch (purchaseResult) {
case AdaptyPurchaseResultSuccess(profile: final profile):
// successful purchase
break;
case AdaptyPurchaseResultPending():
// purchase is pending
break;
case AdaptyPurchaseResultUserCancelled():
// user cancelled the purchase
break;
default:
break;
}
}Ví dụ sự kiện (Nhấn để mở rộng)
void paywallViewDidFinishPurchase(AdaptyUIPaywallView view,
AdaptyPaywallProduct product,
AdaptyPurchaseResult purchaseResult) {
// product — AdaptyPaywallProduct:
product.vendorProductId; // 'premium_monthly'
switch (purchaseResult) {
case AdaptyPurchaseResultSuccess(profile: final profile):
// profile — AdaptyProfile:
profile.accessLevels['premium']?.isActive; // true
profile.accessLevels['premium']?.expiresAt; // DateTime(2027, 2, 15, 10, 30)
break;
case AdaptyPurchaseResultPending():
// no additional data
break;
case AdaptyPurchaseResultUserCancelled():
// no additional data
break;
}
}Chúng tôi khuyến nghị đóng màn hình trong trường hợp đó. Tham khảo Phản hồi các hành động nút để biết chi tiết về cách đóng màn hình paywall.
Hoàn tất điều hướng thanh toán web
Phương thức này được gọi sau khi có lần thử mở web paywall cho một sản phẩm cụ thể. Điều này bao gồm cả các lần điều hướng thành công và thất bại:
void paywallViewDidFinishWebPaymentNavigation(AdaptyUIPaywallView view,
AdaptyPaywallProduct? product,
AdaptyError? error) {
}Tham số:
| Tham số | Mô tả |
|---|---|
| product | Một AdaptyPaywallProduct mà web paywall được mở cho. Có thể là null. |
| error | Một đối tượng AdaptyError nếu điều hướng web paywall thất bại; null nếu điều hướng thành công. |
Ví dụ về sự kiện (Nhấn để mở rộng)
void paywallViewDidFinishWebPaymentNavigation(AdaptyUIPaywallView view,
AdaptyPaywallProduct? product,
AdaptyError? error) {
// product — AdaptyPaywallProduct?:
product?.vendorProductId; // 'premium_monthly'
if (error == null) {
// navigation succeeded
} else {
// error — AdaptyError:
error.code; // AdaptyErrorCode.networkFailed (2005)
error.message; // 'Network request failed'
error.detail; // platform-specific underlying error, or null
}
}Mua hàng thất bại
Phương thức này được gọi khi một giao dịch mua thất bại (ví dụ: do lỗi thanh toán hoặc lỗi mạng). Nó không kích hoạt khi người dùng chủ động huỷ hoặc giao dịch đang chờ xử lý — những trường hợp đó được xử lý bởi paywallViewDidFinishPurchase:
void paywallViewDidFailPurchase(AdaptyUIPaywallView view,
AdaptyPaywallProduct product,
AdaptyError error) {
}Ví dụ sự kiện (Nhấn để mở rộng)
void paywallViewDidFailPurchase(AdaptyUIPaywallView view,
AdaptyPaywallProduct product,
AdaptyError error) {
// product — AdaptyPaywallProduct:
product.vendorProductId; // 'premium_monthly'
// error — AdaptyError:
error.code; // AdaptyErrorCode.productPurchaseFailed (1006)
error.message; // 'Product purchase failed.'
error.detail; // platform-specific underlying error, or null
}Bắt đầu khôi phục
Nếu người dùng khởi động quá trình khôi phục, phương thức này sẽ được gọi:
void paywallViewDidStartRestore(AdaptyUIPaywallView view) {
}Khôi phục thành công
Nếu việc khôi phục giao dịch thành công, phương thức này sẽ được gọi:
void paywallViewDidFinishRestore(AdaptyUIPaywallView view, AdaptyProfile profile) {
}Ví dụ sự kiện (Nhấn để mở rộng)
void paywallViewDidFinishRestore(AdaptyUIPaywallView view, AdaptyProfile profile) {
// profile — AdaptyProfile:
profile.accessLevels['premium']?.isActive; // true
profile.accessLevels['premium']?.expiresAt; // DateTime(2027, 2, 15, 10, 30)
profile.subscriptions['premium_monthly']?.isActive; // true
profile.subscriptions['premium_monthly']?.expiresAt; // DateTime(2027, 2, 15, 10, 30)
}Chúng tôi khuyến nghị đóng màn hình nếu người dùng đã có accessLevel yêu cầu. Tham khảo chủ đề Trạng thái gói đăng ký để biết cách kiểm tra và chủ đề Xử lý hành động nút để biết cách đóng màn hình paywall.
Khôi phục thất bại
Nếu việc khôi phục giao dịch thất bại, phương thức này sẽ được gọi:
void paywallViewDidFailRestore(AdaptyUIPaywallView view, AdaptyError error) {
}Ví dụ sự kiện (Nhấp để mở rộng)
void paywallViewDidFailRestore(AdaptyUIPaywallView view, AdaptyError error) {
// error — AdaptyError:
error.code; // AdaptyErrorCode.receiveRestoredTransactionsFailed (1011)
error.message; // 'Error occurred in the process of restoring purchases.'
error.detail; // platform-specific underlying error, or null
}Tải dữ liệu và hiển thị
Lỗi tải sản phẩm
Nếu bạn không truyền mảng sản phẩm trong quá trình khởi tạo, AdaptyUI sẽ tự động lấy các đối tượng cần thiết từ server. Nếu thao tác này thất bại, AdaptyUI sẽ báo lỗi bằng cách gọi phương thức sau:
void paywallViewDidFailLoadingProducts(AdaptyUIPaywallView view, AdaptyError error) {
}Ví dụ sự kiện (Nhấn để mở rộng)
void paywallViewDidFailLoadingProducts(AdaptyUIPaywallView view, AdaptyError error) {
// error — AdaptyError:
error.code; // AdaptyErrorCode.productRequestFailed (1002)
error.message; // 'Unable to fetch available In-App Purchase products at the moment.'
error.detail; // platform-specific underlying error, or null
}Lỗi khi hiển thị
Nếu xảy ra lỗi trong quá trình render giao diện, lỗi đó sẽ được báo cáo thông qua phương thức này. Theo mặc định (từ v3.15.2), paywall sẽ tự động bị đóng khi gặp lỗi render, nhưng bạn có thể ghi đè hành vi này nếu cần.
void paywallViewDidFailRendering(AdaptyUIPaywallView view, AdaptyError error) {
// Default behavior: view.dismiss()
// Override with custom logic if needed, for example:
// - Log the error
// - Show an error message to the user
}Ví dụ sự kiện (Nhấn để mở rộng)
void paywallViewDidFailRendering(AdaptyUIPaywallView view, AdaptyError error) {
// error — AdaptyError:
error.code; // AdaptyErrorCode.jsException (4105)
error.message; // 'An exception was thrown from JS during AdaptyUI flow execution.'
error.detail; // platform-specific underlying error, or null
// Default behavior: view.dismiss()
}Trong trường hợp bình thường, các lỗi này không nên xảy ra, vì vậy nếu bạn gặp phải, hãy cho chúng tôi biết.