Xử lý lỗi trong iOS SDK

Adapty SDK có wrapper riêng cho mọi loại lỗi, gọi là AdaptyError. Về cơ bản, mọi lỗi được SDK trả về đều là AdaptyError. Nó có hai thuộc tính hữu ích: originalError và adaptyErrorCode, được mô tả bên dưới.

originalError chứa lỗi gốc trong trường hợp bạn cần làm việc trực tiếp với nó. Có thể là SKError, NSError hoặc Swift Error thông thường. Thuộc tính này là tùy chọn vì một số lỗi có thể được tạo trực tiếp bởi SDK, chẳng hạn như dữ liệu không nhất quán hoặc thiếu dữ liệu, và sẽ không có lỗi gốc mà wrapper ban đầu được xây dựng xung quanh.

adaptyErrorCode có thể được dùng để xử lý các vấn đề thường gặp, ví dụ:

  • thông tin xác thực không hợp lệ
  • lỗi mạng
  • thanh toán bị huỷ
  • vấn đề thanh toán
  • biên lai không hợp lệ
  • và nhiều hơn nữa

Việc kiểm tra lỗi theo mã cụ thể và xử lý phù hợp khá đơn giản.

do {
    let info = try await Adapty.makePurchase(product: product)
} catch {
    if error.adaptyErrorCode == .paymentCancelled {
        // purchase was cancelled
        // you can offer discount to your user or remind them later
    }
}
Tip

Bật verbose logs trước khi debug. Hầu hết các AdaptyError đều bọc một lỗi StoreKit, mạng hoặc backend bên dưới. Khi bật verbose logs (Adapty.logLevel = .verbose — xem Logging), lỗi đó sẽ được in ra console, thường cho bạn biết nguyên nhân thực sự. Thuộc tính originalError luôn có giá trị bất kể log level — verbose logs chỉ đơn giản là hiển thị nó ra console.

Important

Nếu các giải pháp này không giải quyết được vấn đề của bạn, hãy xem Vấn đề khác để biết các bước cần thực hiện trước khi liên hệ hỗ trợ, giúp chúng tôi hỗ trợ bạn hiệu quả hơn.

Lỗi StoreKit

LỗiMãGiải pháp
unknown0Mã lỗi cho biết đã xảy ra lỗi không xác định hoặc không mong đợi.
Thử lại hoặc xem phần Các vấn đề khác.
clientInvalid1Mã lỗi này cho biết client không được phép thực hiện hành động đã thử.
paymentCancelled2

Mã lỗi này cho biết người dùng đã hủy yêu cầu thanh toán.

Không cần thực hiện hành động nào, nhưng về mặt logic kinh doanh, bạn có thể cung cấp ưu đãi cho người dùng hoặc nhắc nhở họ sau.

paymentInvalid3Lỗi này cho biết một trong các tham số thanh toán không được App Store nhận dạng.
paymentNotAllowed4Mã lỗi này cho biết người dùng không được phép ủy quyền thanh toán.
storeProductNotAvailable5Mã lỗi này cho biết sản phẩm yêu cầu không có sẵn trong cửa hàng.
Thử cài đặt lại ứng dụng.
cloudServicePermissionDenied6Mã lỗi này cho biết người dùng chưa cho phép truy cập thông tin dịch vụ Cloud.
cloudServiceNetworkConnectionFailed7Mã lỗi này cho biết thiết bị không thể kết nối với mạng.
cloudServiceRevoked8Mã lỗi này cho biết người dùng đã thu hồi quyền sử dụng dịch vụ cloud này.
privacyAcknowledgementRequired9Mã lỗi này cho biết người dùng chưa xác nhận chính sách bảo mật của Apple.
unauthorizedRequestData10Mã lỗi này cho biết ứng dụng đang cố sử dụng một thuộc tính mà nó không có quyền entitlement cần thiết.
invalidOfferIdentifier11

identifier của ưu đãi không hợp lệ. Ví dụ: bạn chưa thiết lập ưu đãi với identifier đó trong App Store, hoặc bạn đã thu hồi ưu đãi.

Hãy đảm bảo bạn đã thiết lập các ưu đãi mong muốn trong AppStore Connect và truyền vào một offer identifier hợp lệ.

invalidSignature12Mã lỗi này cho biết chữ ký trong payment discount không hợp lệ.
missingOfferParams13Mã lỗi này cho biết các tham số bị thiếu trong payment discount.
invalidOfferPrice14Mã lỗi này cho biết mức giá bạn đã chỉ định trong App Store Connect không còn hợp lệ. Các ưu đãi luôn phải thể hiện mức giá được giảm.
noProductIDsFound1000

Lỗi này cho biết không có sản phẩm nào bạn yêu cầu trên paywall có thể mua được trong App Store, dù chúng đã được liệt kê ở đó. Lỗi này đôi khi đi kèm với cảnh báo InvalidProductIdentifiers. Nếu cảnh báo xuất hiện mà không có lỗi, hãy bỏ qua nó.

Nếu bạn gặp lỗi này, hãy làm theo các bước trong phần Sửa lỗi Code-1000 noProductIDsFound.

productRequestFailed1002Không thể tải danh sách sản phẩm khả dụng lúc này.
cantMakePayments1003In-app purchase không được cho phép trên thiết bị này. Xem hướng dẫn khắc phục sự cố.
cantReadReceipt1005

Không có receipt hợp lệ trên thiết bị. Vấn đề này có thể xảy ra trong quá trình kiểm thử sandbox.

Trong sandbox, bạn sẽ không có file receipt hợp lệ cho đến khi thực sự thực hiện một giao dịch mua, vì vậy hãy đảm bảo bạn đã mua ít nhất một lần trước khi truy cập nó. Khi kiểm thử sandbox, cũng hãy đảm bảo bạn đã đăng nhập trên thiết bị bằng tài khoản Apple sandbox hợp lệ.

productPurchaseFailed1006Mua sản phẩm thất bại. Lỗi này bao bọc một lỗi StoreKit bên dưới — đọc originalError (hoặc bật verbose logs để xem trong console) để biết nguyên nhân thực sự. Lỗi được bao bọc thường là một trong các mã StoreKit 0–14 trong bảng trên — phổ biến nhất là paymentCancelled, paymentInvalid, paymentNotAllowed, hoặc invalidOfferPrice. Nếu không xác định được nguyên nhân cụ thể, hãy thử sandbox profile mới; nếu vẫn thất bại, hãy liên hệ hỗ trợ Apple.
refreshReceiptFailed1010Thao tác làm mới receipt thất bại.
fetchSubscriptionStatusFailed1020Không thể lấy trạng thái gói đăng ký từ App Store.
unknownTransactionId1030Mã định danh giao dịch không xác định.
paymentPendingError1050Thanh toán hiện đang chờ xử lý.
billingPlanUnavailable1060Sản phẩm không cung cấp gói thanh toán được yêu cầu trên thiết bị này. Gói cam kết 12 tháng yêu cầu iOS 26.4 trở lên và ứng dụng được build bằng Xcode 26.5 trở lên.

Lỗi mạng

LỗiMãGiải pháp
notActivated2002Adapty SDK chưa được kích hoạt.
Thường gặp nhất khi màn hình splash hoặc một hook UI sớm gọi các phương thức Adapty trước khi Adapty.activate hoàn thành. Triệu chứng này không ổn định và có thể không tái hiện trên simulator vì thời gian thực thi trên thiết bị thật khác nhau. Hãy chờ completion handler hoặc kết quả async của activate trước khi gọi bất kỳ SDK call nào khác. Xem Thứ tự gọi trong iOS SDK để biết toàn bộ trình tự.
badRequest2003Yêu cầu không hợp lệ.
Với getPaywall, nguyên nhân phổ biến nhất là placement được yêu cầu không tồn tại trong ứng dụng mà API key của bạn thuộc về. Hãy kiểm tra lại xem placement ID có được sao chép chính xác không và API key cùng placement có đến từ cùng một ứng dụng trên Adapty Dashboard không.
serverError2004Lỗi máy chủ.
Thử lại sau một khoảng thời gian. Nếu vấn đề vẫn chưa được giải quyết, hãy liên hệ đội ngũ hỗ trợ Adapty.
Mã này cũng bao gồm trường hợp bị giới hạn tốc độ: nếu bạn gọi cùng một endpoint quá thường xuyên (ví dụ: cập nhật hồ sơ người dùng liên tục), máy chủ sẽ phản hồi với mã 429 và SDK sẽ chặn endpoint đó cho đến khi khoảng thời gian retry kết thúc.
networkFailed2005Lỗi này cho thấy có vấn đề với kết nối mạng trên thiết bị của người dùng.
Hãy thử tắt VPN hoặc chuyển từ mạng di động sang WiFi hoặc ngược lại.
decodingFailed2006Lỗi này cho thấy quá trình giải mã phản hồi thất bại — SDK nhận được dữ liệu mà nó không thể phân tích.
Nếu lỗi xảy ra khi SDK tải tệp dự phòng cục bộ, tệp đó cũ hơn so với phiên bản SDK mong đợi: hãy tải tệp mới từ trang Placements. Sự không khớp phiên bản của paywall dự phòng cũng có thể hiển thị dưới dạng lỗi 3001.
encodingFailed2009Lỗi này cho thấy quá trình mã hóa yêu cầu thất bại.

Lỗi chung

LỗiMãGiải pháp
analyticsDisabled3000Không thể xử lý các sự kiện analytics vì bạn đã tắt tính năng này.
wrongParam3001Lỗi này cho biết một số tham số của bạn không đúng.
Nếu bạn đang dùng Paywall Builder cũ và không thể hiển thị paywall do lỗi này, hãy bật Show on device trong builder đó.
Nguyên nhân khác có thể là phiên bản file dự phòng cục bộ không khớp với phiên bản SDK. Hãy tải file mới từ dashboard.
activateOnceError3005Không thể gọi phương thức .activate nhiều hơn một lần.
profileWasChanged3006Hồ sơ người dùng đã bị thay đổi trong quá trình thực hiện thao tác.
Điều này xảy ra khi một phương thức được gọi trong khi Adapty.identify vẫn đang chạy — lệnh gọi đang thực thi sẽ tác động lên một hồ sơ sắp bị thay thế, và SDK từ chối nó. Hãy luôn await identify (hoặc dùng completion handler của nó) trước bất kỳ lệnh gọi nào liên quan đến hành động người dùng. Xem Thứ tự gọi trong iOS SDK.
unsupportedData3007Lỗi này cho biết định dạng dữ liệu không được SDK hỗ trợ.
unidentifiedUserLogout3020Không thể gọi phương thức logout cho người dùng chưa được xác định.
fetchTimeoutError3101Lỗi này cho biết thao tác tải dữ liệu đã hết thời gian chờ.
operationInProgress3201Một thao tác khác cùng loại vẫn đang chạy.
Được trả về bởi showStoreMessages khi một lệnh gọi trước đó vẫn đang hiển thị thông báo App Store. Hãy chờ lệnh đó hoàn tất rồi thử lại.
resolverFailure3202SDK không thể tìm thấy tài nguyên mà thao tác cần.
Được trả về bởi phương thức UIKit showStoreMessages khi bạn không truyền window scene và không có scene nào đang hoạt động ở foreground. Hãy truyền scene một cách tường minh, hoặc gọi lại phương thức khi ứng dụng đang ở foreground.
operationInterrupted9000Thao tác này đã bị hệ thống ngắt.

Lần fetch chậm ngay sau updateProfile

Nếu bạn thiết lập thuộc tính tùy chỉnh bằng updateProfile rồi fetch một placement trong cùng phiên đó, SDK có thể tính hash phân khúc của placement từ các thuộc tính chưa được đồng bộ xong. SDK sẽ thử lại sau khi hash phân khúc được làm mới, vì vậy triệu chứng là fetch chậm hơn chứ không phải lỗi. Fetch chỉ thất bại khi lần thử lại vẫn không khớp, tức là dữ liệu thuộc tính chưa được ghi xong.

Để tránh việc thử lại, hãy await updateProfile trước khi fetch. Xem Thứ tự gọi trong iOS SDK.

Các vấn đề khác

Nếu bạn vẫn chưa tìm được giải pháp, các bước tiếp theo có thể là:

  • Nâng cấp SDK lên phiên bản mới nhất: Chúng tôi luôn khuyến nghị nâng cấp lên các phiên bản SDK mới nhất vì chúng ổn định hơn và bao gồm các bản sửa lỗi đã biết.
  • Liên hệ đội hỗ trợ hoặc nhờ giúp đỡ từ các lập trình viên khác trong diễn đàn hỗ trợ.
  • Liên hệ đội hỗ trợ qua support@adapty.io hoặc qua chat: Nếu bạn chưa sẵn sàng nâng cấp SDK hoặc việc nâng cấp không giúp ích, hãy liên hệ đội hỗ trợ của chúng tôi. Lưu ý rằng vấn đề của bạn sẽ được giải quyết nhanh hơn nếu bạn bật verbose logging và chia sẻ logs với đội ngũ. Bạn cũng có thể đính kèm các đoạn code liên quan.