PlatformHostApiImpl.swift 6.17 KB
import Foundation
import AuthenticationServices
import StoreKit
import UIKit
import WebKit

class PriceFormatter{
    static func formatPrice(_ price: Decimal, currencyCode: String) -> String {
        let formatter = NumberFormatter()
        formatter.numberStyle = .currency
        formatter.currencyCode = currencyCode
        formatter.minimumFractionDigits = 2
        formatter.maximumFractionDigits = 2

        return formatter.string(from: price as NSDecimalNumber) ?? "\(price)"
    }
    
    static func currencySymbol(for currencyCode: String) -> String {

        let formatter = NumberFormatter()

        formatter.numberStyle = .currency

        formatter.currencyCode = currencyCode

//        formatter.locale = Locale(identifier: "zh_CN")

        return formatter.currencySymbol

    }
}

/**
 * PlatformApi iOS implementation.
 *
 * 组装完整 User-Agent格式与 Android 端保持一致
 * `{systemWebViewUA} doublefeel/{versionCode}({versionName})(Apple##Apple##{model}; iOS{osVersion}; {height}x{width})(huawei)`
 */
final class PlatformHostApiImpl: PlatformHostApi {
    func updateLoginInfo(jsonString: String, baseUrl: String) throws {
        AppShared.shared.baseUrl = baseUrl
        if let data = jsonString.data(using: .utf8){
            do{
                let model = try JSONDecoder().decode(FlutterUserSummary.self, from: data)
                AppShared.shared.userSummary = model
            }catch{
                DebugLogger.log(desc: error.localizedDescription)
            }
        }
    }
    
    func requestAppleProductInfo(productId: String, baseUnit: Int64, completion: @escaping (Result<AppleProductInfo?, any Error>) -> Void) {
        Task {
            do {
                let product = try await AppShared.shared.payment.requestProducts(productId)
                let isTrialPeriod = await AppShared.shared.payment.isFreeTrail(product: product)
                let originPrice = product.price
                var displayPrice = product.displayPrice
                var price = originPrice
                if let introductoryOffer = product.subscription?.introductoryOffer{
                    price = introductoryOffer.price
                    displayPrice = introductoryOffer.displayPrice
                }else if let offer = product.subscription?.promotionalOffers.first(where: { $0.id == product.id }){
                    price = offer.price
                    displayPrice = offer.displayPrice
                }
                
                let unitPrice = price/Decimal(baseUnit)
                let currencyCode = product.priceFormatStyle.currencyCode
                
                let productInfo = AppleProductInfo(
                    productId: product.id,
                    originPriceDescription: product.displayPrice,
                    priceDescription: displayPrice,
                    originPrice: NSDecimalNumber(decimal: originPrice * 100).doubleValue,
                    price: NSDecimalNumber(decimal: price * 100).doubleValue,
                    unitPrice: PriceFormatter.formatPrice(unitPrice, currencyCode: currencyCode),
                    currencyCode: PriceFormatter.currencySymbol(for: currencyCode),
                    isTrialPeriod: isTrialPeriod
                )
                print("[PlatformHostApiImpl.requestAppleProductInfo] return: \(productInfo)")
                completion(.success(productInfo))
            } catch StoreKitError.productNotFound {
                print("[PlatformHostApiImpl.requestAppleProductInfo] return: nil")
                completion(.success(nil))
            } catch {
                print("[PlatformHostApiImpl.requestAppleProductInfo] error: \(error.localizedDescription)")
                completion(.failure(error))
            }
        }
    }
    
    func performApplePayment(productId: String, uuid: String, completion: @escaping (Result<AppleProductPaymentResult?, any Error>) -> Void) {
        Task {
            let result = await AppShared.shared.payment.purchase(productId, uuidString: uuid)
            print("[PlatformHostApiImpl.performApplePayment] return: \(result)")
            completion(.success(result))
        }
    }
    
    private var appleSignInCoordinator: AppleSignInCoordinator?

    func requestAppleSignIn(completion: @escaping (Result<AppleSignInModel?, any Error>) -> Void) {
        DispatchQueue.main.async { [weak self] in
            guard let self else {
                print("[PlatformHostApiImpl.requestAppleSignIn] error: \(PlatformHostApiError.deallocated.localizedDescription)")
                completion(.failure(PlatformHostApiError.deallocated))
                return
            }

            let provider = ASAuthorizationAppleIDProvider()
            let request = provider.createRequest()
            request.requestedScopes = [.fullName, .email]

            guard let presentationAnchor = AppleSignInCoordinator.currentPresentationAnchor() else {
                print("[PlatformHostApiImpl.requestAppleSignIn] error: \(PlatformHostApiError.missingPresentationAnchor.localizedDescription)")
                completion(.failure(PlatformHostApiError.missingPresentationAnchor))
                return
            }

            let coordinator = AppleSignInCoordinator(presentationAnchor: presentationAnchor) { [weak self] result in
                self?.appleSignInCoordinator = nil
                switch result {
                case .success(let model):
                    print("[PlatformHostApiImpl.requestAppleSignIn] return: \(String(describing: model))")
                case .failure(let error):
                    print("[PlatformHostApiImpl.requestAppleSignIn] error: \(error.localizedDescription)")
                }
                completion(result)
            }
            appleSignInCoordinator = coordinator

            let controller = ASAuthorizationController(authorizationRequests: [request])
            controller.delegate = coordinator
            controller.presentationContextProvider = coordinator
            controller.performRequests()
        }
    }
    
    func getFullUserAgent() throws -> String {
        let userAgent = AppShared.shared.agent.finalUA
        print("[PlatformHostApiImpl.getFullUserAgent] return: \(userAgent)")
        return userAgent
    }
}