Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

verifying iOS in app purchase receipt with C#

I am verifying my ios in app purchase receipt on my server using C# web service

I got receipt as string by doing below in Xcode:

- (void) completeTransaction: (SKPaymentTransaction *)transaction
{
    NSString* receiptString = [[NSString alloc] initWithString:transaction.payment.productIdentifier];

    NSLog(@"%@",receiptString);

    NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];

    NSData *receipt = [NSData dataWithContentsOfURL:receiptURL];

    NSString *jsonObjectString = [receipt base64EncodedStringWithOptions:0];

}

and I am sending that string(receipt) to my C# web service as parameter. Here is my web service method:

[WebMethod(Description = "Purchase Item Verify")]
public string PurchaseItem(string receiptData)
 {
    string returnmessage = "";

    try
    {
        var json = "{ 'receipt-data': '" + receiptData + "'}";

        ASCIIEncoding ascii = new ASCIIEncoding();
        byte[] postBytes = Encoding.UTF8.GetBytes(json);

        HttpWebRequest request;
        request = WebRequest.Create("https://sandbox.itunes.apple.com/verifyReceipt") as HttpWebRequest;
        request.Method = "POST";
        request.ContentType = "application/json";
        request.ContentLength = postBytes.Length;

        Stream postStream = request.GetRequestStream();
        postStream.Write(postBytes, 0, postBytes.Length);
        postStream.Close();

        var sendresponse = (HttpWebResponse)request.GetResponse();

        string sendresponsetext = "";
        using (var streamReader = new StreamReader(sendresponse.GetResponseStream()))
        {
            sendresponsetext = streamReader.ReadToEnd();
        }
        returnmessage = sendresponsetext;

    }
    catch (Exception ex)
    {
        ex.Message.ToString();
    }
    return returnmessage;
}

It always return {"status":21002}. I have been searching for two days , but still can't find out the solution. Can someone help me, what am i wrong ?

**I am testing on sandbox that is why i use sandbox URL. I can verify the transaction receipt within my app.

like image 661
ZAW WIN NAING Avatar asked Apr 08 '14 09:04

ZAW WIN NAING


People also ask

How do I verify my Apple receipt?

Use the production URL https://buy.itunes.apple.com/verifyReceipt when your app is live in the App Store. For more information on these endpoints, see verifyReceipt. Verify your receipt first with the production URL; then verify with the sandbox URL if you receive a 21007 status code.

How do I get an iOS app purchase receipt?

To access your Apple invoices:Go to “Settings” =>[your name] => iTunes Store and App Store. Select your Apple ID, then touch “View” the Apple ID. (You may be prompted to log in using your Apple ID). Scan the screen upwards to access Purchase History, then tap this option.


2 Answers

I got solution

The final code that works for me is:

 public string PurchaseItem(string receiptData)
{
    string returnmessage = "";
    try
    {
       // var json = "{ 'receipt-data': '" + receiptData + "'}";

        var json = new JObject(new JProperty("receipt-data", receiptData)).ToString();

        ASCIIEncoding ascii = new ASCIIEncoding();
        byte[] postBytes = Encoding.UTF8.GetBytes(json);

      //  HttpWebRequest request;
        var request = System.Net.HttpWebRequest.Create("https://sandbox.itunes.apple.com/verifyReceipt");
        request.Method = "POST";
        request.ContentType = "application/json";
        request.ContentLength = postBytes.Length;

        //Stream postStream = request.GetRequestStream();
        //postStream.Write(postBytes, 0, postBytes.Length);
        //postStream.Close();

        using (var stream = request.GetRequestStream())
        {
            stream.Write(postBytes, 0, postBytes.Length);
            stream.Flush();
        }

      //  var sendresponse = (HttpWebResponse)request.GetResponse();

        var sendresponse = request.GetResponse();

        string sendresponsetext = "";
        using (var streamReader = new StreamReader(sendresponse.GetResponseStream()))
        {
            sendresponsetext = streamReader.ReadToEnd().Trim();
        }
        returnmessage = sendresponsetext;

    }
    catch (Exception ex)
    {
        ex.Message.ToString();
    }
    return returnmessage;

Spending two and half days just to change a method. Thanks GOD.

like image 108
ZAW WIN NAING Avatar answered Sep 22 '22 16:09

ZAW WIN NAING


Here's an alternative asynchronous implementation using HTTPClient:

public static async Task<string> CheckReceiptWithAppStore()
    {
        string responseStr = null;

        string uri = "https://sandbox.itunes.apple.com/verifyReceipt";

        string receiptData = // Get your receipt from wherever you store it

        var json = new JObject(new JProperty("receipt-data", receiptData), 
            new JProperty("password", "paste-your-shared-secret-here")).ToString();

        using (var httpClient = new HttpClient())
        {        

            if (receiptData != null)
            {
                HttpContent content = new StringContent(json);

                try
                {
                    Task<HttpResponseMessage> getResponse = httpClient.PostAsync(uri, content);
                    HttpResponseMessage response = await getResponse;
                    responseStr = await response.Content.ReadAsStringAsync();
                }
                catch (Exception e)
                {
                    Console.WriteLine("Error verifying receipt: " + e.Message);
                }
            }
        }

        return responseStr;
    }

The shared secret is not required for non-subscription based purchases.

like image 34
Nande Avatar answered Sep 19 '22 16:09

Nande