Checking the receipt after an in-app purchase
A new receipt is automatically downloaded once a SKPaymentTransaction is changing state to SKPaymentTransactionStatePurchased. Thus, it is only a matter of validating and parsing the app-receipt again once that happens. This is checked in the delegate function-(void)paymentQueue:(SKPaymentQueue*)queue updatedTransactions:(NSArray*)transactions
Getting the in-app part of the receipt
Below is an extension of listing 1-6 in the guide. The text in bold is the extra statements needed to hold the in-app purchase data
size_t i;
OCTET_STRING_t *iap[2];
int iap_cnt=0;
for (i = 0; i < payload->list.count; i++) {
ReceiptAttribute_t *entry;
entry = payload->list.array[i];
switch (entry->type) {
case 2:
bundle_id = &entry->value;
break;
case 3:
bundle_version = &entry->value;
break;
case 4:
opaque = &entry->value;
break;
case 5:
hash = &entry->value;
break;
case 17:
iap[iap_cnt]=&entry->value;
iap_cnt ++ ;
break;
}
}
The iap[] array should be large enough to hold references to all possible in-app purchases, i.e. the total number of products configured for the app. Each of the OCTET_STRING_t references now hold a new ASN.1 structure that holds the information on the in-app purchase. It is important that the free_struct call is not called before these new structures have been parsed. To parse the structures, a function like the following can be used:
static inline void getIAP(OCTET_STRING_t **iap, int iap_cnt){
Payload_t *payload=NULL;
asn_dec_rval_t rval;
int i,n;
for (n=0; n < iap_cnt; n++){
OCTET_STRING_t *this_iap = iap[n];
payload = NULL;
rval = asn_DEF_Payload.ber_decoder(NULL,&asn_DEF_Payload,(void **)&payload, this_iap->buf,this_iap->size,0);
if (rval.code != RC_OK){
NSLog(@"Failed to decode payload at index %d",n);
asn_DEF_Payload.free_struct(&asn_DEF_Payload,payload,0);
continue;
}
for (i=0; i < payload->list.count; i++){
ReceiptAttribute_t *entry;
entry = payload->list.array[i];
switch (entry->type) {
case AR_IAP_PRODUCT_ID:{
const char *id1 = "com.yourdomain.yourproduct1";
const char *id2 = "com.yourdomain.yourproduct2";
if (strcmp(id1, (char *)entry->value.buf+2)==0){
enableFeature(0);
}
if (strcmp(id2, (char *)entry->value.buf+2)==0){
enableFeature(1);
}
}
break;
default:
break;
}
}
asn_DEF_Payload.free_struct(&asn_DEF_Payload,payload,0);
}
}
It is important that the payload is set to NULL for each iteration - otherwise it is not possible to free the payload in each iteration. Note that the OCTET_STRINGs should be parsed from offset 0, while the product IDs are found from offset 2. After this function is called, the full app receipt structure can be freed.
Ingen kommentarer:
Send en kommentar