2011-02-25 9 views
18

Sto cercando di implementare i nuovi abbonamenti Auto rinnovabili utilizzando l'acquisto In App, ma non sono sicuro su come o quando verificare se l'utente è attualmente iscritto. La mia comprensione è che quando l'utente inizialmente sottoscrive l'app può utilizzare la data di acquisto insieme alla data dell'abbonamento per calcolare per quanto tempo il loro abbonamento sarebbe durato. Cosa succede dopo questa data? Come verifichiamo se l'utente si è auto-rinnovato o cancellato?Come effettuare il check in L'acquisto automatico L'abbonamento rinnovabile è valido

Se utilizzo restoreCompletedTransactions per ottenere una transazione e una ricevuta per ogni rinnovo, all'utente verrà richiesto di immettere la propria password iTunes. Questo significa che se hanno acquistato un abbonamento di 7 giorni dovranno inserire la password ogni 7 giorni quando l'app controlla se l'abbonamento è ancora valido?

+0

Questo link https://stackoverflow.com/questions/22680059/auto-renewable-subscription-in-ios7/45220204#45220204 potrebbe aiutare tu. –

risposta

7

vedere questo per docs:

http://developer.apple.com/library/ios/#documentation/NetworkingInternet/Conceptual/StoreKitGuide/VerifyingStoreReceipts/VerifyingStoreReceipts.html#//apple_ref/doc/uid/TP40008267-CH104-SW1

se si vuole verificare su di esso da un server web, si esegue il ping loro API e restituisce lo stato della sottoscrizione auto-rinnovabile e informazioni circa l'ultimo pagamento.

Se si è sul dispositivo, probabilmente è necessario chiamare restoreCompletedTransactions che suppongo richieda la password.

Non vedo nessun altro metodo. Suppongo che dal dispositivo sia possibile verificare l'abbonamento contattando lo stesso servizio Web utilizzato sul lato server? Non so come i pro ei contro di ciò.

+1

Penso che l'accordo sia - devi comunque usare un componente server dal momento che devi fornire anche il segreto condiviso come parametro nella chiamata al server Apple quando esegui il controllo di validità della ricevuta. Non penso che dovresti mettere il segreto condiviso nel tuo codice client dell'app iOS perché il segreto non sarebbe più molto segreto ... – Jonny

+0

È la password segreta condivisa necessaria per convalidare lo scontrino sia su sandbox che su produzione modalità per gli abbonamenti al rinnovo automatico? @Jonny –

+0

Salve, hai detto "ping la loro API e restituisce lo stato della sottoscrizione auto-rinnovabile e le informazioni sull'ultimo pagamento" Qual è l'API per controllare lo stato nel lato server? – Yohan

3

Sto iniziando una campagna intorno a questo problema. Ecco la mia osservazione e campagna:

Al momento del rinnovo automatico, l'App Store chiama lo paymentQueue e pubblica una transazione. La transazione viene registrata con transaction.transactionState==SKPaymentTransactionStateRestored.

Il problema è che purtroppo questo viene pubblicato solo su un dispositivo. Un secondo dispositivo non ottiene la pubblicazione. Pertanto, per rilevare il rinnovo automatico, o piuttosto per rilevare la mancanza di un riavvio automatico e negare al dispositivo un abbonamento permanente, è necessario eseguire un restoreCompletedTransaction o "http pubblicare un JSON codificato a 64 bit contenente l'ultima transazione". Se il primo, l'utente deve dare la propria password; è invadente, come hai sottolineato sopra. In quest'ultimo caso, è necessaria molta codifica aggiuntiva. Quindi, la mia domanda è ... perché non StoreKit avere un comando:

(non esiste) - [[SKPaymentQueue defaultQueue] restoreAttachedTransactions:(NSArray *)transactions];

Questo comando scorrere proprio come un restoreCompletedTransactions ma sarebbe ripristinare solo le transazioni collegate e, più importante, non richiederebbe il log-in da parte dell'utente. Ha la stessa protezione di sicurezza del "http post a JSON codificato a 64 bit contenente l'ultima transazione" e consente di completare l'intero processo In App Purchase in anziché richiedere il codice di pubblicazione web.

Se questo ha senso per te, ti preghiamo di suggerire come ottenere questo ad Apple .... grazie.

+0

Quello che descrivi sembra corrispondere a quello che ho trovato con l'ulteriore riproduzione quindi ho deciso di implementare solo un componente server. Anche se è un problema perché richiede una codifica aggiuntiva, il componente server è piuttosto semplice e probabilmente vale la pena per la traccia di controllo e la verifica della ricevuta. –

12

Oggi ho problemi con questo problema.

Seguire Apple doc qui, ho usato questo modo per controllare l'abbonamento è scaduto o meno. La mia idea: utente Apple REST API di risposta: (tempo di richiesta + tempo scaduto) per controllare scaduto o no

+ (BOOL)checkInAppPurchaseStatus 
{ 
    // Load the receipt from the app bundle. 
    NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL]; 
    NSData *receipt = [NSData dataWithContentsOfURL:receiptURL]; 
    if (receipt) { 
     BOOL sandbox = [[receiptURL lastPathComponent] isEqualToString:@"sandboxReceipt"]; 
     // Create the JSON object that describes the request 
     NSError *error; 
     NSDictionary *requestContents = @{ 
              @"receipt-data": [receipt base64EncodedStringWithOptions:0],@"password":@"SHARE_SECRET_CODE" 
              }; 
     NSData *requestData = [NSJSONSerialization dataWithJSONObject:requestContents 
                   options:0 
                   error:&error]; 

     if (requestData) { 
      // Create a POST request with the receipt data. 
      NSURL *storeURL = [NSURL URLWithString:@"https://buy.itunes.apple.com/verifyReceipt"]; 
      if (sandbox) { 
       storeURL = [NSURL URLWithString:@"https://sandbox.itunes.apple.com/verifyReceipt"]; 
      } 
      NSMutableURLRequest *storeRequest = [NSMutableURLRequest requestWithURL:storeURL]; 
      [storeRequest setHTTPMethod:@"POST"]; 
      [storeRequest setHTTPBody:requestData]; 

      BOOL rs = NO; 
      //Can use sendAsynchronousRequest to request to Apple API, here I use sendSynchronousRequest 
      NSError *error; 
      NSURLResponse *response; 
      NSData *resData = [NSURLConnection sendSynchronousRequest:storeRequest returningResponse:&response error:&error]; 
      if (error) { 
       rs = NO; 
      } 
      else 
      { 
       NSDictionary *jsonResponse = [NSJSONSerialization JSONObjectWithData:resData options:0 error:&error]; 
       if (!jsonResponse) { 
        rs = NO; 
       } 
       else 
       { 
        NSLog(@"jsonResponse:%@", jsonResponse); 

        NSDictionary *dictLatestReceiptsInfo = jsonResponse[@"latest_receipt_info"]; 
        long long int expirationDateMs = [[dictLatestReceiptsInfo valueForKeyPath:@"@max.expires_date_ms"] longLongValue]; 
        long long requestDateMs = [jsonResponse[@"receipt"][@"request_date_ms"] longLongValue]; 
        NSLog(@"%lld--%lld", expirationDateMs, requestDateMs); 
        rs = [[jsonResponse objectForKey:@"status"] integerValue] == 0 && (expirationDateMs > requestDateMs); 
       } 
      } 
      return rs; 
     } 
     else 
     { 
      return NO; 
     } 
    } 
    else 
    { 
     return NO; 
    } 
} 

Spero che questo aiuto.

+1

Grazie. Supplementi consigliati: NSURLSession tutorial in modo da poter eseguire un controllo asincrono https://www.raywenderlich.com/110458/nsurlsession-tutorial-getting-started e anche su come testare gli abbonamenti Sandbox (verso la fine): https: // savvyapps .com/blog/come-setup-test-auto-rinnovabili-subscription-ios-app – Philosophistry

4

È meglio utilizzare una soluzione locale prima di effettuare qualsiasi chiamata all'API Apple. Ogni volta che viene eseguita l'app, è buona norma convalidare la ricevuta locale e, se è necessario verificare se un utente ha l'abbonamento attivo, è possibile recuperare gli acquisti dalla ricevuta locale e scoprire che l'acquisto è ancora attivo per oggi .

Ho implementato una piccola libreria scritta in Swift per semplificare il funzionamento locale della ricevuta in-app. È possibile recuperare facilmente l'oggetto che rappresenta la ricevuta (InAppReceipt) e recuperare un acquisto attivo/tutti gli acquisti.

Sentitevi liberi di usare. Github link

Ecco un esempio di risolvere il problema:

import TPInAppReceipt 

do { 
    let receipt = try InAppReceiptManager.shared.receipt() 

    //retrive active auto renewable subscription for a specific product and date 
    let purchase = receipt.activeAutoRenewableSubscriptionPurchases(ofProductIdentifier: "ProductName", forDate: Date()) 

    //retrive all auto renewable subscription purchases for a specific product 
    let allAutoRenewableSubscriptionPurchases = receipt.purchases(ofProductIdentifier: "productName").filter({ return $0.isRenewableSubscription }) 
} catch { 
    print(error) 
} 
Problemi correlati