Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Diagnostics] Add check_intro_trial event #4264

Draft
wants to merge 6 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions Sources/Diagnostics/DiagnosticsEvent.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ extension DiagnosticsEvent {
case httpRequestPerformed
case customerInfoVerificationResult
case maxEventsStoredLimitReached
case applePurchaseAttempt
case checkIntroTrial

}

Expand All @@ -41,9 +43,13 @@ extension DiagnosticsEvent {
case verificationResultKey
case endpointNameKey
case responseTimeMillisKey
case storeKitVersion
case successfulKey
case responseCodeKey
case backendErrorCodeKey
case errorMessageKey
case errorCodeKey
case skErrorDescriptionKey
case eTagHitKey

}
Expand Down
54 changes: 54 additions & 0 deletions Sources/Diagnostics/DiagnosticsTracker.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,22 @@ protocol DiagnosticsTrackerType {
resultOrigin: HTTPResponseOrigin?,
verificationResult: VerificationResult) async

@available(iOS 15.0, tvOS 15.0, macOS 12.0, watchOS 8.0, *)
func trackPurchaseRequest(wasSuccessful: Bool,
storeKitVersion: StoreKitVersion,
errorMessage: String?,
errorCode: Int?,
storeKitErrorDescription: String?) async

@available(iOS 15.0, tvOS 15.0, macOS 12.0, watchOS 8.0, *)
// swiftlint:disable:next function_parameter_count
func trackCheckIntroTrial(wasSuccessful: Bool,
storeKitVersion: StoreKitVersion,
errorMessage: String?,
errorCode: Int?,
storeKitErrorDescription: String?,
responseTime: TimeInterval) async

}

@available(iOS 15.0, tvOS 15.0, macOS 12.0, watchOS 8.0, *)
Expand Down Expand Up @@ -91,6 +107,44 @@ final class DiagnosticsTracker: DiagnosticsTrackerType {
)
}

func trackPurchaseRequest(wasSuccessful: Bool,
storeKitVersion: StoreKitVersion,
errorMessage: String?,
errorCode: Int?,
storeKitErrorDescription: String?) async {
await track(
DiagnosticsEvent(eventType: .applePurchaseAttempt,
properties: [
.successfulKey: AnyEncodable(wasSuccessful),
.storeKitVersion: AnyEncodable("store_kit_\(storeKitVersion.debugDescription)"),
.errorMessageKey: AnyEncodable(errorMessage),
.errorCodeKey: AnyEncodable(errorCode),
.skErrorDescriptionKey: AnyEncodable(storeKitErrorDescription)
],
timestamp: self.dateProvider.now())
)
}

func trackCheckIntroTrial(wasSuccessful: Bool,
storeKitVersion: StoreKitVersion,
errorMessage: String?,
errorCode: Int?,
storeKitErrorDescription: String?,
responseTime: TimeInterval) async {
await track(
DiagnosticsEvent(eventType: .applePurchaseAttempt,
properties: [
.successfulKey: AnyEncodable(wasSuccessful),
.storeKitVersion: AnyEncodable("store_kit_\(storeKitVersion.debugDescription)"),
.errorMessageKey: AnyEncodable(errorMessage),
.errorCodeKey: AnyEncodable(errorCode),
.skErrorDescriptionKey: AnyEncodable(storeKitErrorDescription),
.responseTimeMillisKey: AnyEncodable(responseTime * 1000)
],
timestamp: self.dateProvider.now())
)
}

}

@available(iOS 15.0, tvOS 15.0, macOS 12.0, watchOS 8.0, *)
Expand Down
10 changes: 10 additions & 0 deletions Sources/Diagnostics/Networking/DiagnosticsEventsRequest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ private extension DiagnosticsEvent.EventType {
case .httpRequestPerformed: return "http_request_performed"
case .customerInfoVerificationResult: return "customer_info_verification_result"
case .maxEventsStoredLimitReached: return "max_events_stored_limit_reached"
case .applePurchaseAttempt: return "apple_purchase_attempt"
case .checkIntroTrial: return "check_intro_trial"
}

}
Expand All @@ -80,12 +82,20 @@ private extension DiagnosticsEvent.DiagnosticsPropertyKey {
return "endpoint_name"
case .responseTimeMillisKey:
return "response_time_millis"
case .storeKitVersion:
return "store_kit_version"
case .successfulKey:
return "successful"
case .responseCodeKey:
return "response_code"
case .backendErrorCodeKey:
return "backend_error_code"
case .errorMessageKey:
return "error_message"
case .errorCodeKey:
return "error_code"
case .skErrorDescriptionKey:
return "sk_error_description"
case .eTagHitKey:
return "etag_hit"
}
Expand Down
23 changes: 23 additions & 0 deletions Sources/Error Handling/ErrorUtils.swift
Original file line number Diff line number Diff line change
Expand Up @@ -544,6 +544,29 @@ enum ErrorUtils {
fileName: fileName, functionName: functionName, line: line)
}

static func invalidReceiptError(
fileName: String = #fileID, functionName: String = #function, line: UInt = #line
) -> PurchasesError {
return ErrorUtils.error(with: .invalidReceiptError,
fileName: fileName, functionName: functionName, line: line)
}

/**
* Constructs an Error with the ``ErrorCode/invalidReceiptError`` code.
*
* - Note: This error is used when there is a problem with the receipt.
*/
static func invalidReceiptError(
withMessage message: String, error: Error? = nil,
fileName: String = #fileID, functionName: String = #function, line: UInt = #line
) -> PurchasesError {
let errorCode = ErrorCode.invalidReceiptError
return ErrorUtils.error(with: errorCode,
message: message,
underlyingError: error,
fileName: fileName, functionName: functionName, line: line)
}

}

extension ErrorUtils {
Expand Down
51 changes: 51 additions & 0 deletions Sources/Error Handling/SKError+Extensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,57 @@ extension SKError: PurchasesErrorConvertible {

}

extension SKError.Code {
var trackingDescription: String {
switch self {
case .unknown:
return "unknown"
case .clientInvalid:
return "client_invalid"
case .paymentCancelled:
return "payment_cancelled"
case .paymentInvalid:
return "payment_invalid"
case .paymentNotAllowed:
return "payment_not_allowed"
case .storeProductNotAvailable:
return "store_product_not_available"
case .cloudServicePermissionDenied:
return "cloud_service_permission_denied"
case .cloudServiceNetworkConnectionFailed:
return "cloud_service_network_connection_failed"
case .cloudServiceRevoked:
return "cloud_service_revoked"
case .privacyAcknowledgementRequired:
return "privacy_acknowledgement_required"
case .unauthorizedRequestData:
return "unauthorized_request_data"
case .invalidOfferIdentifier:
return "invalid_offer_identifier"
case .invalidSignature:
return "invalid_signature"
case .missingOfferParams:
return "missing_offer_params"
case .invalidOfferPrice:
return "invalid_offer_price"
case .overlayCancelled:
return "overlay_cancelled"
case .overlayInvalidConfiguration:
return "overlay_invalid_configuration"
case .overlayTimeout:
return "overlay_timeout"
case .ineligibleForOffer:
return "ineligible_for_offer"
case .unsupportedPlatform:
return "unsupported_platform"
case .overlayPresentedInBackgroundScene:
return "overlay_presented_in_background_scene"
@unknown default:
return "unknown_future_error"
}
}
}

private extension SKError {

enum UndocumentedCode: Int {
Expand Down
23 changes: 23 additions & 0 deletions Sources/Error Handling/StoreKitError+Extensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,29 @@ extension StoreKitError: PurchasesErrorConvertible {
}
}

var trackingDescription: String {
switch self {
case .unknown:
return "unknown"
case .userCancelled:
return "user_cancelled"
case .networkError(let urlError):
return "network_error_\(urlError.code.rawValue)"
case .systemError(let error):
return "system_error_\(String(describing: error))"
case .notAvailableInStorefront:
return "not_available_in_storefront"
case .notEntitled:
if #available(iOS 15.4, macOS 12.3, tvOS 15.4, watchOS 8.5, visionOS 1.0, *) {
return "not_entitled"
} else {
return "unknown"
}
@unknown default:
return "unknown_future_error"
}
}

}

@available(iOS 15.0, tvOS 15.0, watchOS 8.0, macOS 12.0, *)
Expand Down
6 changes: 4 additions & 2 deletions Sources/Purchasing/IntroEligibilityCalculator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ class IntroEligibilityCalculator {

func checkEligibility(with receiptData: Data,
productIdentifiers candidateProductIdentifiers: Set<String>,
completion: @escaping ([String: IntroEligibilityStatus], Error?) -> Void) {
completion: @escaping ([String: IntroEligibilityStatus], PurchasesError?) -> Void) {
guard candidateProductIdentifiers.count > 0 else {
completion([:], nil)
return
Expand Down Expand Up @@ -73,8 +73,10 @@ class IntroEligibilityCalculator {
completion(result, nil)
}
} catch {
let message = Strings.customerInfo.checking_intro_eligibility_locally_error(error: error).description
let purchasesError = ErrorUtils.invalidReceiptError(withMessage: message, error: error)
Logger.error(Strings.customerInfo.checking_intro_eligibility_locally_error(error: error))
completion([:], error)
completion([:], purchasesError)
return
}
}
Expand Down
6 changes: 4 additions & 2 deletions Sources/Purchasing/Purchases/Purchases.swift
Original file line number Diff line number Diff line change
Expand Up @@ -500,7 +500,8 @@ public typealias StartPurchaseBlock = (@escaping PurchaseCompletedBlock) -> Void
storeKit2StorefrontListener: StoreKit2StorefrontListener(delegate: nil),
storeKit2ObserverModePurchaseDetector: storeKit2ObserverModePurchaseDetector,
storeMessagesHelper: storeMessagesHelper,
diagnosticsSynchronizer: diagnosticsSynchronizer
diagnosticsSynchronizer: diagnosticsSynchronizer,
diagnosticsTracker: diagnosticsTracker
)
} else {
return .init(
Expand Down Expand Up @@ -533,7 +534,8 @@ public typealias StartPurchaseBlock = (@escaping PurchaseCompletedBlock) -> Void
backend: backend,
currentUserProvider: identityManager,
operationDispatcher: operationDispatcher,
productsManager: productsManager)
productsManager: productsManager,
diagnosticsTracker: diagnosticsTracker)
)

let paywallCache: PaywallCacheWarmingType?
Expand Down
Loading