2016-07-08 2 views
0

반응이있는 기본 앱에 앱을 구매하려고합니다. react-native-in-app-utils을 시도하고 Swift에서 네이티브 모듈을 생성했습니다. 둘 다 작동하지만 둘 다 매우 불안정 해 보입니다. Xcode 콘솔에서 오류없이 무작위로 충돌합니다. 테스트 비행에서 훨씬 안정적이지만 여전히 충돌이 발생하며 운이나 이유가없는 것으로 보입니다. 크래시의 대부분은 구매시 발생하지만 Apple에서 구매를 검색하거나 구매를 복원 할 때도 많이 발생합니다. 다음은 내가 응답 할 수있는 Objective C 브릿지가있는 신속한 코드입니다.React Native/Swift - In 구매 sandbox 및 testflight에서 무작위로 코드가 충돌 함

// Create Product List 
struct ProductList { 
    static let monthlySub  : String = "monthlysubscription" 
    static let threeMonthlySub : String = "threemonthlysubscription" 
    static let sixMonthlySub : String = "sixmonthlysubscription" 
    static let yearlySub  : String = "yearlysubscription" 

    static let products = [monthlySub, threeMonthlySub, sixMonthlySub, yearlySub] 
} 

@objc(StoreManager) 
class StoreManager: NSObject { 

    var loadedProducts: Dictionary<String, SKProduct> = [:] 
    // callback holders defined as optionals 
    var purchaseCallbackHolder: RCTResponseSenderBlock? = nil 
    var productsCallbackHolder: RCTResponseSenderBlock? = nil 
    var restoreCallbackHolder: RCTResponseSenderBlock? = nil 

    override init() { 
    super.init() 
    SKPaymentQueue.defaultQueue().addTransactionObserver(self) 
    } 

    @objc func getProductList(name: String, callback successCallback: RCTResponseSenderBlock){ 
    // check payments allowed 
    if SKPaymentQueue.canMakePayments() { 
     // products from static struct 
     let products = NSSet(array: ProductList.products); 
     // When request completes, calls the SKProductsRequestDelegate 
     let request = SKProductsRequest(productIdentifiers: products as! Set<String>); 
     productsCallbackHolder = successCallback 
     request.delegate = self; 
     request.start(); 
    } 
    } 

    @objc func purchaseProduct(productIdentifier: String, callback successCallback: RCTResponseSenderBlock) { 
    let product = loadedProducts[productIdentifier as String]! 
    let payment = SKPayment(product: product) 
    // add callback to holder 
    purchaseCallbackHolder = successCallback 
    // Triggers SKPaymentTransactionObserver 
    SKPaymentQueue.defaultQueue().addPayment(payment) 
    } 

    @objc func restorePurchases(name:String, callback successCallback: RCTResponseSenderBlock){ 
    restoreCallbackHolder = successCallback 
    print("Restoring Purchases") 
    SKPaymentQueue.defaultQueue().restoreCompletedTransactions() 
    } 


    @objc func validatePurchases(name:String, callback successCallback: RCTResponseSenderBlock) -> Void { 

    let receiptUrl = NSBundle.mainBundle().appStoreReceiptURL 
    let receipt: NSData = NSData(contentsOfURL:receiptUrl!)! 
    let receiptdata: NSString = receipt.base64EncodedStringWithOptions(NSDataBase64EncodingOptions(rawValue: 0)) 

    // Pass Base64 encoded string back to JS 
    successCallback([receiptdata]) 

    } 

    func updateWithProducts(products: [SKProduct]) { 

    var productIdentifiers: Dictionary<String, NSNumber> = [:] 
    for product in products { 
     loadedProducts[product.productIdentifier] = product 
     productIdentifiers[product.productIdentifier] = product.price 
    } 
    productsCallbackHolder?([productIdentifiers]) 
    } 


} 

extension StoreManager: SKProductsRequestDelegate { 
    func productsRequest(request: SKProductsRequest, didReceiveResponse response: SKProductsResponse) { 
    // products retrieved from App store 
    let appProducts = response.products 
    if appProducts.count != 0 { 
     for product in appProducts{ 
     print(product.productIdentifier) 
     } 
     print(appProducts) 
     updateWithProducts(appProducts) 
    } 
    else { 
     // return error/info to react native 
     print("no products received from store") 
    } 
    } 
} 
extension StoreManager: SKPaymentTransactionObserver { 
    func paymentQueue(queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) { 
    print("Received Payment Transaction Response from Apple"); 
    for transaction:AnyObject in transactions { 
     // check object is a transaction first 
     if let trans:SKPaymentTransaction = transaction as? SKPaymentTransaction{ 
     switch trans.transactionState { 
     case .Purchased: 
      print("Product Purchased"); 
      SKPaymentQueue.defaultQueue().finishTransaction(transaction as! SKPaymentTransaction) 
      break; 
     case .Failed: 
      print("Purchased Failed"); 
      SKPaymentQueue.defaultQueue().finishTransaction(transaction as! SKPaymentTransaction) 
      break; 
     case .Restored: 
      print("Purchases Restored"); 
      SKPaymentQueue.defaultQueue().finishTransaction(transaction as! SKPaymentTransaction) 
     default: 
      break; 
     } 
     } 
     // invoke any callback waiting to be called 
     purchaseCallbackHolder?([]) 
     purchaseCallbackHolder = nil 
     restoreCallbackHolder?([]) 
     restoreCallbackHolder = nil 
    } 

    } 
} 

도움이 될만한 정보가 있습니까?

업데이트

: 나는

AppName[1788:581487] *** -[StoreManager respondsToSelector:]: message sent to deallocated instance 0x14d43f80 
(lldb) bt 
* thread #4: tid = 0x8df6f, 0x25750ffe CoreFoundation`___forwarding___ + 530, queue = 'com.facebook.react.StoreManagerQueue', stop reason = EXC_BREAKPOINT (code=EXC_ARM_BREAKPOINT, subcode=0xdefe) 
    * frame #0: 0x25750ffe CoreFoundation`___forwarding___ + 530 
    frame #1: 0x2567b298 CoreFoundation`_CF_forwarding_prep_0 + 24 
    frame #2: 0x2f103f1e StoreKit`__NotifyObserverAboutChanges + 66 
    frame #3: 0x2565bc08 CoreFoundation`CFArrayApplyFunction + 36 
    frame #4: 0x2f103ecc StoreKit`-[SKPaymentQueue _notifyObserversAboutChanges:sendUpdatedDownloads:] + 128 
    frame #5: 0x2f1028e8 StoreKit`-[SKPaymentQueue addPayment:] + 320 
    frame #6: 0x00106438 AppName`StoreManager.purchaseProduct(productIdentifier="iosmonthlysubscription799", successCallback=0x00106694 AppName`partial apply forwarder for reabstraction thunk helper from @callee_unowned @convention(block) (@unowned Swift.ImplicitlyUnwrappedOptional<__ObjC.NSArray>) -> (@unowned()) to @callee_owned (@owned Swift.ImplicitlyUnwrappedOptional<Swift.Array<Swift.AnyObject>>) -> (@unowned()) with unmangled suffix ".40" at inAppPayments.swift, self=0x14d0a990) ->()) ->() + 1168 at inAppPayments.swift:54 
    frame #7: 0x00106634 AppName`@objc StoreManager.purchaseProduct(String, callback : ([AnyObject]!) ->()) ->() + 240 at inAppPayments.swift:0 
    frame #8: 0x25752664 CoreFoundation`__invoking___ + 68 
    frame #9: 0x256778bc CoreFoundation`-[NSInvocation invoke] + 292 
    frame #10: 0x2567b356 CoreFoundation`-[NSInvocation invokeWithTarget:] + 50 
    frame #11: 0x001672d6 AppName`-[RCTModuleMethod invokeWithBridge:module:arguments:](self=0x14fdba90, _cmd="invokeWithBridge:module:arguments:", bridge=0x14faa1a0, module=0x14d0a990, [email protected]"2 elements") + 1636 at RCTModuleMethod.m:489 
    frame #12: 0x001abaea AppName`-[RCTBatchedBridge _handleRequestNumber:moduleID:methodID:params:](self=0x14faa1a0, _cmd="_handleRequestNumber:moduleID:methodID:params:", i=6, moduleID=77, methodID=3, [email protected]"2 elements") + 926 at RCTBatchedBridge.m:987 
    frame #13: 0x001aae44 AppName`__33-[RCTBatchedBridge handleBuffer:]_block_invoke.452(.block_descriptor=<unavailable>) + 1028 at RCTBatchedBridge.m:915 
    frame #14: 0x00b9bba6 libdispatch.dylib`_dispatch_call_block_and_release + 10 
    frame #15: 0x00ba64aa libdispatch.dylib`_dispatch_queue_drain + 2014 
    frame #16: 0x00b9ede2 libdispatch.dylib`_dispatch_queue_invoke + 282 
    frame #17: 0x00ba799e libdispatch.dylib`_dispatch_root_queue_drain + 426 
    frame #18: 0x00ba77f0 libdispatch.dylib`_dispatch_worker_thread3 + 100 
    frame #19: 0x2547ee0c libsystem_pthread.dylib`_pthread_wqthread + 1024 
    frame #20: 0x2547e9fc libsystem_pthread.dylib`start_wqthread + 8 

아래의 충돌 스택 추적 내 콜백 참조 선택적 항목이기 때문에 충돌 것 같다 있나요? 이것은 Objective C bridge에 의해 호출되는 Swift입니다. 나는 목표 C가 선택의 개념이 없다고 생각한다.

var purchaseCallbackHolder: RCTResponseSenderBlock? = nil

이 할 수있는 더 좋은 방법이 있나요?

StoreKit__NotifyObserverAboutChanges 

뾰족에게 : 나는 그들 중 하나를 내 스택 추적에 내가지고 있다고 오류를 고개를

override init() { 
    super.init() 
    SKPaymentQueue.defaultQueue().addTransactionObserver(self) 
    } 


    deinit { 
    if SKPaymentQueue.canMakePayments() { 
     SKPaymentQueue.defaultQueue().removeTransactionObserver(self) 
    } 
    } 

: 다시 한번 감사

답변

관련 문제