How can I check purchase id which was sent by user to me from his orders list?
For example, he can send something like: M1VYXX7VX7 (as written in his purchases list in appstore) and ask to return his purchase (may be he had deleted his app accidentally),
But when I get order information inside of my code (through SKPaymentTransaction) I have no access to that identifier. Then only ID i have looks like: 1000000020706713.
So is there any ways to validate that purchase ID using information which was sent to me by app store?
Thanks.
Read Verifying Store Receipts in the In-App Purchase Programming Guide. According to the documentation:
To verify the receipt, perform the following steps:
Retrieve the receipt data. On iOS, this is the value of the transaction's transactionReceipt property. On OS X, this is the entire contents of the receipt file inside the application bundle. Encode the receipt data using base64 encoding.
Create a JSON object with a single key named receipt-data and the string you created in step 1. Your JSON code should look like this:
{
"receipt-data" : "(receipt bytes here)"
}
Post the JSON object to the App Store using an HTTP POST request. The URL for the store is https://buy.itunes.apple.com/verifyReceipt.
The response received from the App Store is a JSON object with two keys, status and receipt. It should look something like this:
{
"status" : 0,
"receipt" : { (receipt here) }
}
If the value of the status key is 0, this is a valid receipt. If the value is anything other than 0, this receipt is invalid.
Read the article for more details.
Related
I have a paid iOS App.
I need to get the original_application_version number (the first version purchased by the user) from the Apple AppStore Receipt.
To get the receipt, when my app loads, I use checkReceiptFromAppStore() function:
func checkReceiptFromAppStore() {
let receipt = self.getReceipt()
print("receipt Data is: \(receipt)") // prints this: receipt Data is: Optional(5141 bytes)
}
getReceipt() function is the following:
func getReceipt() -> Data? {
if Bundle.main.appStoreReceiptURL != nil {
print("app receipt: \(Bundle.main.appStoreReceiptURL)")
do {
let receiptData = try Data(contentsOf: Bundle.main.appStoreReceiptURL!)
return receiptData
} catch {
print("error converting receipt to Data: \(error.localizedDescription)")
}
}
return nil
}
I've watched WWDC 2017 Advanced StoreKit video about In App purchases and receipt validation and WWDC 2013 Video about using Receipts, read different
resources related to my problem (this, this, this, this, this, this, and this...), but I still don't understand what to do next to get the
"original_application_version" from the App Store Receipt. I need only this field and don't understand why is it so hard to get it.
I've read this too: https://developer.apple.com/library/content/releasenotes/General/ValidateAppStoreReceipt/Chapters/ReceiptFields.html
I think that the receipt is not nil as long at when I run print("receipt Data is: (receipt)") it prints this: receipt Data is: Optional(5141 bytes)
I can suppose that I should parse the receipt to get that field. Can I do it using Decodable? Is there the easiest way to get this original_application_version field? Is it possible to do this without a receipt validation?
I need to get the original_application_version field only to detect the number of the first version bought by the user. If you know any other solutions to get the first purchased version number, I'd be glad to hear them.
I'm developing in Xcode 9, Swift 4, iOS 11
Any answers appreciated, thanks.
All receipt fields are in binary format within application receipt. You should use any kind of app receipt decoder in order to get original_application_version. It is always good thing to validate app receipt before using its contents. For example, you can use RMStore framework (RMStore). It contains receipt validator as well as decoder. Example Obj-C source:
RMAppReceipt *appReceipt = RMAppReceipt.bundleReceipt;
if (appReceipt != nil &&
[appReceipt.originalAppVersion length] > 0 &&
![appReceipt.originalAppVersion isEqualToString:#"1.0"]) {
//Process your original app version
} else {
//Probably it is sandbox mode or app install via Xcode
//Or maybe you should force app receipt refresh
}
I'm trying to verify the receipt for an in app purchase with my own node server. I used the information available on this page:
https://developer.apple.com/library/content/releasenotes/General/ValidateAppStoreReceipt/Chapters/ValidateRemotely.html
I send the receipt-data in a base64 encoded string as the value of the key receipt data. But everytime I get the Status 21002 which means that the receipt-data property if malformed or missing.
Im using the request module for node to send the request and this is what my code looks like:
var payload = {
"receipt-data":receipt_data,
"password":password
}
request.post(
config.appStoreReceiptVerificationUrl,
{
form:payload
},
function(err, response, data_str)
{// handle response here}
This is the data in the receipt_data variable: http://textuploader.com/d0tup
What could be the problem?
i have succesfully integrating react-native-fcm and
i am getting notification when i am sending from firebase console (in foreground,background,and killed state of app)
but when i am sending it from our server with custom data i cannot recieved when app is in (killed,background) state
i have also tried content-availble:true in data object
below is the notification data which i am sending
{
aps = {
"content-available" = 1;
};
body = "Get a free T-Shirt #WROGN on every purchase via Shopholix. T&C apply.";
"gcm.message_id" = "0:1475746605785619%9a4a567a9a4a567a";
"gcm.notification.data" = "{\"image\":\"http:\\/\\/res.cloudinary.com\\/saurabh\\/image\\/upload\\/v1469791885\\/media\\/yljgxgmfg1qbulxzwakm.png\",\"user_type\":\"all\",\"screen\":\"store\",\"id\":\"56d7e33ce69f7c8f06550002\",\"title\":\"Shopholix\",\"message\":\"Get a free T-Shirt #WROGN on every purchase via Shopholix. T&C apply.\",\"body\":\"Get a free T-Shirt #WROGN on every purchase via Shopholix. T&C apply.\"}";
"gcm.notification.priority" = high;
id = 56d7e33ce69f7c8f06550002;
image = "http://res.cloudinary.com/saurabh/image/upload/v1469791885/media/yljgxgmfg1qbulxzwakm.png";
message = "Get a free T-Shirt #WROGN on every purchase via Shopholix. T&C apply.";
screen = store;
title = Shopholix;
"user_type" = all;
}
Any help would be appreciated
Thanks,
Your content_available is set to 1. I'm pretty sure when using FCM, you should use true or false. Correct me if I'm reading your payload structure in a wrong way, but are you specifying the content_available separate from the GCM payload?
Also, the priority parameter should be outside the notification payload parameter.
See here for more details.
Were you able to resolve your issue?
Looking at the JSON, if it is exactly how you're sending it, then it is not well formed. All of the keys need to be strings surrounded by quotes. And each key-value pair needs to be comma-separated, not semi-colon.
I'm currently working on ApplePay and we are decrypting the token on our own server.
The decryption of token is done but there is a few things I don't quite understand. From the Getting-Started-with-Apple-Pay we know that:
"The payment token encapsulates the
information needed to complete a payment
transaction, including the device-specific
account number, the amount, and a unique,
one-time-use cryptogram."
But from the Payment Token Format Reference, there are 8 things contained in a token:
applicationPrimaryAccountNumber
applicationExpirationDate
currencyCode
transactionAmount
cardholderName
deviceManufacturerIdentifier
paymentDataType
paymentData
We get the accountNumber and the amount, but which one of those is the cryptogram?
Is it the last one, paymentData, since the other 7 really don't look like cryptogram? If not, how could we get this cryptogram?
I'd also like to ask what should we do after we get the cryptogram? Should we send the cryptogram and accountNumber to the acquirer?
Thank you!
If you look at the Payment Token Format
You will see that the token contains a paymentDataType string and a paymentData dictionary.
If the paymentDataType is "3DSecure" then the paymentData dictionary will contain a key onlinePaymentCryptogram which is the cryptogram string.
This must be submitted to your payment gateway if you are submitting a 3-D Secure transaction.
I'm trying to implement an application with auto-renewable subscription. Users should pay to access all functions of my application. I already use Parse as backend for my application. It provides some API methods for inAppPurchases but there is nothing said about auto-renewable type. The only thing I have found is some two years old threads in the blog it is said that receipt verification was implemented only for downloadable purchases.
I have tried to use as it called in docs "Simple purchase" and it works fine but I can't figure out how can I check if my user already bought subscription or not.
Does anybody know is there way to do it via Parse API or This should implemented in another way?
As mentioned, receipt validation is only built into the Parse SDK for downloadable content, but it is fairly simple to to create a Cloud Code function that POSTs the app receipt to the iTunes Store for validation. Here are the Apple docs for server side validation: Validating Receipts with the App Store
Here is a what a basic function would look like:
Parse.Cloud.define('validateReceipt', function (request, response) {
var receiptAsBase64EncodedString = request.params.receiptData;
var postData = {
method: 'POST',
url: 'http://buy.itunes.apple.com/verifyReceipt',
body: { 'receipt-data': receiptAsBase64EncodedString,
'password': SHARED_SECRET }
}
Parse.Cloud.httpRequest(postData).then(function (httpResponse) {
// httpResponse is a Parse.Cloud.HTTPResponse
var json = httpResponse.data; // Response body as a JavaScript object.
var validationStatus = json.status; // App Store validation status code
var receiptJSON = json.receipt; // Receipt data as a JSON object
// TODO: You'll need to check the IAP receipts to retrieve the
// expiration date of the auto-renewing subscription, and
// determine if it is expired yet.
var subscriptionIsActive = true;
if (subscriptionIsActive) {
return response.success('Subscription Active');
}
else {
return response.error('Subscription Expired');
}
});
});
See Receipt Fields for details on interpreting the receipt JSON. It's fairly straight forward for iOS 7+, but auto-renewing subscription receipts for iOS 6 and earlier are tedious.