Q: How I can detect when this event (currently subscribed) has occurred so that I can process the transaction and grant access to my app.
You detect when the subscription exists via validation with Apple (I use php website code to do this), you get a "status code" response back, and can verify whether it is a code 21006 (subscription is expired), or others (I consider anything other than 0 and 21006 to be an actual error).
The way I do things is I store the transaction details inside a PLIST file which I store in the documents directory.
You could add extra fields to the PLIST such as expiryDates, boolean flags, etc.
This way you have a copy of the receipt, although you should always validate it because it might have expired.
Q: In the paymentQueue:updatedTransactions: method of the observer it
is coming through as a SKPaymentTransactionStateFailed. How do I
distinguish between this type of failure and other failures such as
the user pressing the cancel buttons?
You use a switch statement in the updatedTransactions method to determine the different types of responses.
Example
-(void)paymentQueue:(SKPaymentQueue *)queue restoreCompletedTransactionsFailedWithError:(NSError *)error
{
NSString *message = [NSString stringWithFormat:@"Transaction failed with error - %@", error.localizedDescription];
NSLog(@"Error - %@", message);
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Error"
message:message
delegate:nil
cancelButtonTitle:@"OK"
otherButtonTitles:nil];
[alertView show];
[alertView release];
}
-(void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
{
NSLog(@"updatedTransactions");
for (SKPaymentTransaction *transaction in transactions)
{
switch (transaction.transactionState)
{
case SKPaymentTransactionStatePurchasing:
// take action whilst processing payment
break;
case SKPaymentTransactionStatePurchased:
// take action when feature is purchased
break;
case SKPaymentTransactionStateRestored:
// take action to restore the app as if it was purchased
break;
case SKPaymentTransactionStateFailed:
if (transaction.error.code != SKErrorPaymentCancelled)
{
// Do something with the error
} // end if
break;
default:
break;
} // end switch
} // next
The TransactionStateFailed handles the failures, although I do not code for cancellation as there is no reason for me to do so in my app.
Q: Do I submit the transaction that is returned or do I need to call
restorePreviousTransactions.
I believe StoreKit handles this internally with finishTransaction method and restorePreviousTransaction methods
ie,
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
to finish off transactions
I hope this helps