How can I read offline receipt inpp purchase in ios? - ios

I have implemented Inapp purchase in my app and validating receipt but I have problem with validate receipt when i am on offline.How can i do that?
Following is my code to validate when my interent is connected.
-(void)refreshRecipt
{
NSError *error;
_isUserActive = NO;
NSURL *recieptUrl = [[NSBundle mainBundle]appStoreReceiptURL];
NSError *recieptError;
BOOL isPresent = [recieptUrl checkResourceIsReachableAndReturnError:&recieptError];
if (!isPresent)
{
SKReceiptRefreshRequest *ref = [[SKReceiptRefreshRequest alloc]init];
ref.delegate =self;
[ref start];
return;
}
NSData *reciptData = [NSData dataWithContentsOfURL:recieptUrl];
if (!reciptData)
{
return;
}
dicPayload = [NSMutableDictionary dictionaryWithObject:[reciptData base64EncodedStringWithOptions:0] forKey:#"receipt-data"];
[dicPayload setObject:#"21f843e264474b68b3a81c6b7ca19938" forKey:#"password"];
NSData *requestData = [NSJSONSerialization dataWithJSONObject:dicPayload
options:0
error:&error];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:verifyRecieptURL]];
[request setHTTPMethod:#"POST"];
[request setHTTPBody:requestData];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[NSURLConnection sendAsynchronousRequest:request queue:queue
completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
if (connectionError) {
NSLog(#"error");
} else {
NSError *error;
NSDictionary *jsonResponse = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
if ([jsonResponse objectForKey:#"latest_receipt_info"])
{
NSArray *array = [jsonResponse objectForKey:#"latest_receipt_info"];
NSLog(#"%#",array);
NSDictionary *latestDetail = [array lastObject];
if ([latestDetail objectForKey:#"is_trial_period"])
{
if ([[latestDetail objectForKey:#"is_trial_period"] isEqualToString:#"true"])
{
_isFreeTrialActive = YES;
}
else
{
_isFreeTrialActive = NO;
}
_isUserActive = [self calculateCurrentSubscriptionActive:[latestDetail objectForKey:#"expires_date_ms"]];
if (_isUserActive)
{
NSLog(#"User is active");
_SubscriptionActive = YES;
}
else
{
_SubscriptionActive = NO;
NSLog(#"User is not active");
}
}
else
{
NSLog(#"no purachase done,first time user!");
}
}
}
}];
}
please help me to sort out this.

You can validate you receipt locally, this is how you would do it according to apple documentation:
Validate the Receipt
To validate the receipt, perform the following tests, in order:
1- Locate the receipt.
If no receipt is present, validation fails.
2- Verify that the receipt is properly signed by Apple.
If it is not signed by Apple, validation fails.
3- Verify that the bundle identifier in the receipt matches a hard-coded constant containing the CFBundleIdentifier value you expect in the Info.plist file.
If they do not match, validation fails.
4- Verify that the version identifier string in the receipt matches a hard-coded constant containing the CFBundleShortVersionString value (for macOS) or the CFBundleVersion value (for iOS) that you expect in the Info.plist file.
If they do not match, validation fails.
5- Compute the hash of the GUID as described in Compute the Hash of the GUID.
If the result does not match the hash in the receipt, validation fails.
If all of the tests pass, validation passes.
In order to do so you would first need to decrypt the receipt. For this you can use a library like RMStore. Using this library you can do something like:
- (RMAppReceipt *)validReceipt {
RMAppReceipt *receipt = [RMAppReceipt bundleReceipt];
if (!receipt)
//No receipt
return nil;
if (![receipt.bundleIdentifier isEqualToString:#"Your bundle ID"]) {
//Receipt is invalid
return nil;
}
if (![receipt verifyReceiptHash]) {
//Receipt is invalid
return nil;
}
//Receipt is valid
return receipt;
}
RMAppReceipt contains all information from the receipt.

Related

How to test if Json response includes error or proper json

Explanation: Throughout app, we use a web request method located in AppDelegate.m to fetch data from server. I use a token in all these requests. Sometimes the response from server is the json : {error = "token_not_provided"} or {error = "token_expired"}. I need a way to test if the json includes these errors or the proper json data. If the data sent back is either of these errors, we need to go back to login screen to get a new token upon login. Right now, I have no way to detect these errors in the request method so if they occur, the app will forever crash because there is no way to take you back to login. Here is the request method in App Delegate:
-(void)makeRequest:(NSString*)urlString method:(NSString*)method params:(NSMutableDictionary*)params onComplete:(RequestBlock)callback {
// create the url
NSURL * url = [NSURL URLWithString:[NSString stringWithFormat:#"%#/%#", BASE_URL, urlString]];
NSMutableURLRequest * request = [[NSMutableURLRequest alloc] initWithURL:url];
KeychainItemWrapper *keychainItem = [[KeychainItemWrapper alloc] initWithIdentifier:#"YourAppLogin" accessGroup:nil];
NSString *token = [keychainItem objectForKey:(__bridge id)(kSecAttrAccount)];
if(!token){
token = #"NO_TOKEN";
}
// set the method (GET/POST/PUT/UPDATE/DELETE)
[request setHTTPMethod:method];
[request addValue:[#"Bearer " stringByAppendingString:token] forHTTPHeaderField:#"Authorization"];
// if we have params pull out the key/value and add to header
if(params != nil) {
NSMutableString * body = [[NSMutableString alloc] init];
for (NSString * key in params.allKeys) {
NSString * value = [params objectForKey:key];
[body appendFormat:#"%#=%#&", key, value];
}
[request setHTTPBody:[body dataUsingEncoding:NSUTF8StringEncoding]];
}
// submit the request
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse *response,
NSData *data, NSError *connectionError) {
// do we have data?
if(data && data.length > 0) {
NSMutableDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil];
// if we have a block lets pass it
if(callback) {
callback(json);
}
HERE IS WHERE I WANT TO TEST IF WE HAVE ERROR JSON or PROPER JSON
}
}];
}
If you can modify the interface on your server you could send a bool to identify if the request was successful. Something like "success" = 1 or 0.
To check on the error-message is dangerous, if the message changes your app will crash. If you want to do it anyway you need to check if the key "error" exists and then what it contains.
// Check if key is available.
if ([json.keys containsObject:#"error"]) {
if ([json[#"error"] isEqualToString:#"token_not_privided"] || [json[#"error"] isEqualToString:#"token_expired"]) {
// Token is invalid
} else {
// Something different went wrong.
}
}
// Nothing is wrong, lets inform the caller.
else {
if (callback) {
callback(json);
}
}
You should check on the json and not on the data.

Validating App store receipt gives DrmInvalidArgumentException

I'm following the documentation here.
https://developer.apple.com/library/content/releasenotes/General/ValidateAppStoreReceipt/Chapters/ValidateRemotely.html
I have a receipt-data from my team that I'm trying to validate, they're getting error code 21002 which was malformed JSON. It looks like they had extra parameters appended to the base64 data, so I tried removing those and sending:
- (void)viewDidLoad {
[super viewDidLoad];
NSData *receipt; // Sent to the server by the device
// Create the JSON object that describes the request
NSError *error;
NSDictionary *requestContents = #{
#"receipt-data": #"<<$mybase64data>>", #"password" : #"<<$thepassword>>"};
NSData *requestData = [NSJSONSerialization dataWithJSONObject:requestContents options:0 error:&error];
if (!requestData) { /* ... Handle error ... */ }
// Create a POST request with the receipt data.
NSURL *storeURL = [NSURL URLWithString:#"https://buy.itunes.apple.com/verifyReceipt"];
NSMutableURLRequest *storeRequest = [NSMutableURLRequest requestWithURL:storeURL];
[storeRequest setHTTPMethod:#"POST"];
[storeRequest setHTTPBody:requestData];
// Make a connection to the iTunes Store on a background queue.
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[NSURLConnection sendAsynchronousRequest:storeRequest queue:queue
completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
if (connectionError) {
/* ... Handle error ... */
NSLog(#"conerror %#", connectionError);
} else {
NSError *error;
NSDictionary *jsonResponse = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
NSLog(#"hello %#", jsonResponse);
NSLog(#"error %#", error);
if (!jsonResponse) {
}
}
}];
}
result:
2017-03-03 22:45:47.454 receipttest[89851:352604] hello {
exception = "com.apple.jingle.mzfairplay.validators.DrmInvalidArgumentException";
status = 21002;
}
2017-03-03 22:45:47.455 receipttest[89851:352604] error (null)
Something to keep in mind: In this example the data is sent to Apple straight from the App, but you might do this from a server too. When you testing your server App don't use NSLog() to print your base64 data, NSLog truncates data.
I had this issue when using a receipt from a test user that was a couple days old with a yearly auto-renewable subscription.
I checked the above helpful responses about extra characters etc (I also checked I had supplied my app secret for auto-renewable) with no joy.
In the end I tried creating A NEW SANDBOX user and it worked first time
with no other changes other than the new Receipt!
Hope this helps someone.
I also received the same error response for serveral receipts. The solution for me was to remove all occurrences of \r\n.
Maybe you have the same issue. I still haven't figured out when and why these chars are inserted.
Pay attention to URLENCODE:
- (NSString *)URLEncodedString
{
// CharactersToBeEscaped = #":/?&=;+!##$()~',*";
// CharactersToLeaveUnescaped = #"[].";
NSString *unencodedString = self;
NSString *encodedString = (NSString *)
CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault,
(CFStringRef)unencodedString,
NULL,
(CFStringRef)#"!*'();:#&=+$,/?%#[]",
kCFStringEncodingUTF8));
return encodedString;
}

How to test app store purchase receipt to obtain original application version

I want to load the app purchase receipt on app launch. How can I simulate an app purchase (not an In-App Purchase, but an actual App purchase) so that I'll have a receipt? (I'm trying to go from paid to freemium).
I'm using this code to load the receipts
(BOOL)isAppPreviouslyPurchased {
BOOL wasPreviouslyPurchased = false;
// Load the receipt from the app bundle.
NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];
NSData *receiptData = [NSData dataWithContentsOfURL:receiptURL];
if (receiptData) {
//read purchase version from receipt
NSDictionary *receipt = [NSJSONSerialization JSONObjectWithData:receiptData options:0 error:nil];
NSString *oldVersion = receipt[#"original_application_version"];
float vFloat = [oldVersion floatValue];
if (vFloat < 1.6) {
wasPreviouslyPurchased = true;
}
}
return wasPreviouslyPurchased;
}
First of all : Refresh your receipt
SKReceiptRefreshRequest *request = [[SKReceiptRefreshRequest alloc] init];
request.delegate = self;
[request start];
Add the SKPaymentTransactionObserver protocol and this method
- (void)paymentQueue:(SKPaymentQueue *)queue
updatedTransactions:(NSArray *)transactions
{
for (SKPaymentTransaction *transaction in transactions) {
switch (transaction.transactionState) {
// Call the appropriate custom method for the transaction state.
case SKPaymentTransactionStatePurchasing:
[self showTransactionAsInProgress:transaction deferred:NO];
break;
case SKPaymentTransactionStateDeferred:
[self showTransactionAsInProgress:transaction deferred:YES];
break;
case SKPaymentTransactionStateFailed:
[self failedTransaction:transaction];
break;
case SKPaymentTransactionStatePurchased:
[self completeTransaction:transaction];
break;
case SKPaymentTransactionStateRestored:
[self restoreTransaction:transaction];
break;
default:
// For debugging
NSLog(#"Unexpected transaction state %#", #(transaction.transactionState));
break;
}
}
}
Then, when this method will be called, your receipt will be refreshed ;)
Secondly : You must decrypt the receipt
NSData *receipt; // Sent to the server by the device
// Create the JSON object that describes the request
NSError *error;
NSDictionary *requestContents = #{
#"receipt-data": [receipt base64EncodedStringWithOptions:0]
};
NSData *requestData = [NSJSONSerialization dataWithJSONObject:requestContents
options:0
error:&error];
if (!requestData) { /* ... Handle error ... */ }
// Create a POST request with the receipt data.
NSURL *storeURL = [NSURL URLWithString:#"https://buy.itunes.apple.com/verifyReceipt"];
NSMutableURLRequest *storeRequest = [NSMutableURLRequest requestWithURL:storeURL];
[storeRequest setHTTPMethod:#"POST"];
[storeRequest setHTTPBody:requestData];
// Make a connection to the iTunes Store on a background queue.
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[NSURLConnection sendAsynchronousRequest:storeRequest queue:queue
completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
if (connectionError) {
/* ... Handle error ... */
} else {
NSError *error;
NSDictionary *jsonResponse = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
if (!jsonResponse) { /* ... Handle error ...*/ }
/* ... Send a response back to the device ... */
}
}];
You can decrypt it with this code, but it's not really recommended by Apple. You should call iTunes from your server.
Then, you can call your method with the response returned by Apple server.
Like this (with locally validation, bad way as Apple said)
NSData *receipt; // Sent to the server by the device
// Create the JSON object that describes the request
NSError *error;
NSDictionary *requestContents = #{
#"receipt-data": [receipt base64EncodedStringWithOptions:0]
};
NSData *requestData = [NSJSONSerialization dataWithJSONObject:requestContents
options:0
error:&error];
if (!requestData) { /* ... Handle error ... */ }
// Create a POST request with the receipt data.
NSURL *storeURL = [NSURL URLWithString:#"https://buy.itunes.apple.com/verifyReceipt"];
NSMutableURLRequest *storeRequest = [NSMutableURLRequest requestWithURL:storeURL];
[storeRequest setHTTPMethod:#"POST"];
[storeRequest setHTTPBody:requestData];
// Make a connection to the iTunes Store on a background queue.
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[NSURLConnection sendAsynchronousRequest:storeRequest queue:queue
completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
if (connectionError) {
/* ... Handle error ... */
} else {
NSError *error;
NSDictionary *jsonResponse = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
if (!jsonResponse) { /* ... Handle error ...*/ }
[self isAppPreviouslyPurchased:jsonResponse];
}
}];
-(BOOL)isAppPreviouslyPurchased:(NSDictionary *)receipt {
BOOL wasPreviouslyPurchased = false;
NSString *oldVersion = receipt[#"original_application_version"];
float vFloat = [oldVersion floatValue];
if (vFloat < 1.6) {
wasPreviouslyPurchased = true;
}
return wasPreviouslyPurchased;
}

In-app purchase receipt not sent to server when production

I have been trying to upload a new version of my app containing non-renewing In-app Purchases with no success. It has been revoked for almost two months and i cannot find the problem.
When i'm testing with a sandbox account the purchase goes to my server, i authenticate the receipt and then update my user's status. But when my app goes to review, the reviewer says that my app doesn't deliver user's paid content, but i get not single attempt on my server.
I have made some changes on my Objective-C code hoping that maybe the error could be the timeout, which now i changed to 45.0 seconds. How long it is supposed to be?
I also made some changes to my server code that check if the purchase have been made by a sandbox or production account.
So... this is the method called after SKPaymentTransactionStatePurchased.
#pragma mark pagamento
-(void)completarTransacao:(SKPaymentTransaction *)transacao
{
[SVProgressHUD dismiss];
receipt = [NSData dataWithContentsOfURL:[[NSBundle mainBundle] appStoreReceiptURL]];
if (!receipt)
{
receipt = transacao.transactionReceipt;
}
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
[SVProgressHUD showWithStatus:NSLocalizedString(#"Efetuando assinatura...", nil)];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:[NSString stringWithFormat:#"%#assinaturaplano/", [[NSDictionary dictionaryWithContentsOfFile:configuracoes_plist] objectForKey:#"Dominio"]]] cachePolicy:nil timeoutInterval:45.0];
[request setHTTPMethod:#"POST"];
[request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField: #"Content-Type"];
[request setAllHTTPHeaderFields:[NSHTTPCookie requestHeaderFieldsWithCookies:[[NSHTTPCookieStorage sharedHTTPCookieStorage] cookiesForURL:[NSURL URLWithString:#"http://temp"]]]];
NSString *postString = [NSString stringWithFormat:#"receipt=%#&transactionIdentifier=%#&origem=%#", [receipt.base64Encoding urlencode], transacao.transactionIdentifier, [[NSDictionary dictionaryWithContentsOfFile:[home_documents stringByAppendingPathComponent:#"compra"]] objectForKey:#"origem"]];
[request setHTTPBody:[NSData dataWithBytes:[postString UTF8String] length:postString.length]];
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *erro)
{
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
[SVProgressHUD dismiss];
if ([(NSHTTPURLResponse*)response statusCode] == 200 || [(NSHTTPURLResponse*)response statusCode] == 201)
{
// SUBSCRIPTION CONFIRMED
[SVProgressHUD showSuccessWithStatus:NSLocalizedString(#"Assinatura efetuada com sucesso!", nil)];
[[NSNotificationCenter defaultCenter] postNotificationName:#"atualizarGold" object:nil];
}
else
{
// SUBSCRIPTION NOT CONFIRMED
[SVProgressHUD showErrorWithStatus:NSLocalizedString(#"Assinatura não efetuada. Tente novamente.", nil)];
}
[[SKPaymentQueue defaultQueue] finishTransaction:transacao];
}];
}
My purchase method always goes to else when in review.
Review response
Reasons
2.2: Apps that exhibit bugs will be rejected
----- 2.2 ----- We found that your app exhibited one or more bugs, when reviewed on iPad running iOS 8 and iPhone 5s running iOS 8, on
both Wi-Fi and cellular networks, which is not in compliance with the
App Store Review Guidelines. In App Purchase does not complete. After
users tap on the In App Purchase, enter the Apple ID and password and
confirm the purchase, an error message is produced. The steps to
reproduce are:
1. launch app
2. sign in with the provided credentials
3. select 'Gold Membership'
4. tap '7 days'
5. enter the user's Apple ID and password
6. confirm purchase
7. error message appears
What am i doing wrong? Why does it work only though sandbox?
To find the receipt info i did the following:
// Transaction: SKPaymentTransaction
// storeURL: Sandbox - https://sandbox.itunes.apple.com/verifyReceipt | Production - https://buy.itunes.apple.com/verifyReceipt
-(void)validateTransaction:(SKPaymentTransaction *)transaction storeURL:(NSString *)url
{
receipt = [NSData dataWithContentsOfURL:[[NSBundle mainBundle] appStoreReceiptURL]];
if (!receipt)
{
receipt = transacao.transactionReceipt;
}
NSError *error;
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url]];
[request setHTTPMethod:#"POST"];
[request setHTTPBody:[NSJSONSerialization dataWithJSONObject:#{#"receipt-data": [receipt base64EncodedStringWithOptions:0], #"password" : #"yourpassword"} options:0 error:&error]];
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError)
{
if (!connectionError)
{
NSDictionary *jsonResponse = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
if ([[jsonResponse objectForKey:#"status"] intValue] == 0)
{
NSDictionary *purchaseInfo;
NSArray *inApp = [[jsonResponse objectForKey:#"receipt"] objectForKey:#"in_app"];
if (inApp)
{
for (NSDictionary *receptDictionary in inApp)
{
if ([[receptDictionary objectForKey:#"transaction_id"] isEqualToString:transacao.transactionIdentifier])
{
purchaseInfo = receptDictionary;
break;
}
}
}
// The recent has been found
// Send it to your server
}
else
{
switch ([[jsonResponse objectForKey:#"status"] intValue])
{
case 21003:
// Receipt not authenticated
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
break;
case 21005:
// Server not available
break;
case 21007:
// Sandbox receipt send it to sandbox server
[self validateTransaction:transaction storeURL:#"https://sandbox.itunes.apple.com/verifyReceipt"];
break;
case 21008:
// Production receipt send it to production
[self validateTransaction:transaction storeURL:#"https://buy.itunes.apple.com/verifyReceipt"];
break;
}
}
}
else
{
// It was not possible to connect AppStore
}
}];
}

what receipt for auto-renewable subscription should i validate?

i'm developing the server side of an app with IAP, i know that i need to send the receipt from the app to my server when the user do a subscription, then validate the receipt with the app store for the status, date expiration, etc, & give the user the content.
But my question is, what receipt do i need to check for the renew status? i mean, the first time i check the receipt the app store give me back a receipt, status and a latest receipt, this latest receipt is the one that should i use to check the status the next time or should i use always the original receipt? i been testing with both of them and they give me the same status from the app store but i'm not sure of what is the correct way to doing.
Thanks
Today, I have trouble with this problem.
Follow Apple doc here, I used this way to check subscription is expired or not.
+ (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;
}
}
Hope this help.
after completion of your transaction you will get tansaction & trasaction.reciept for this transaction reciept you want to provide base64 here is the code for this
NSString *jsonObjectString = [self encodeBase64:(uint8_t*)transaction.transactionReceipt.bytes
length:transaction.transactionReceipt.length];
this jsonObjectString will save it to the server and while verifying the receipt you want to provide sharedsecret for this verify this link

Resources