Anderson Bressane
Anderson Bressane

Reputation: 416

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?

Upvotes: 0

Views: 800

Answers (1)

Anderson Bressane
Anderson Bressane

Reputation: 416

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
          }
      }];
 }

Upvotes: 1

Related Questions