I am developing an app purchase in my Flutter project, and I am going to verify my purchase now. On the client side, I pass this parameter:
public class ReceiptVerifyRequest implements Serializable {
@ApiModelProperty(value = "product ID")
@NonNull
private String productId;
@ApiModelProperty(value = "receipt")
@NonNull
private String receipt;
@ApiModelProperty(value = "transaction ID")
@NonNull
private String transactionId;
}
Because I am now is subscribe product and auto renew(SUBSCRIPTION product), so I pick the record from latest_receipt_info
list field on the server side like this:
private void savePayTransactionRecord(JSONArray latestReceiptInfo, IapProduct iapProduct, ReceiptVerifyRequest request) {
if (ApplePayProductType.SUBSCRIPTION.getKey().equals(iapProduct.getProductType())) {
if (latestReceiptInfo == null || latestReceiptInfo.size() == 0) {
return;
}
for (Object item : latestReceiptInfo) {
if (item instanceof JSONObject) {
JSONObject jsonObjectItem = (JSONObject) item;
if (request.getTransactionId().equals(jsonObjectItem.getString("transaction_id"))) {
mapFieldAndSave(jsonObjectItem);
}
}
}
}
}
To my surprise, I could not find any order by using transaction id to match. Why would this happen? Am I doing something wrong? I am following the guide of the Apple manual. What should I do to fix it? What may be causing this situation? By the way, the client transaction id was fetched from purchased id, I read the in app purchase source code of flutter plugin, the purchased id was picked from transaction identify, I think the transaction identify was the transaction id.
Now I am in sandbox, and my subscribe product was 30 days. In sandbox, it was 3 minites, then the server automatic renew the subscribe every 3 minites. for a long time, the latest generate receipt exceed the max value of latest_receipt_info size. so the transaction id not found. Is that the logic right?
so what is the max size of latest_receipt_info
? But he problem is: all my verify transaction could not find in the server latest_receipt_info, it is weird. I already tried use web_order_line_item_id
:
private void savePayTransactionRecord(JSONArray latestReceiptInfo, IapProduct iapProduct, ReceiptVerifyRequest request) {
if (ApplePayProductType.SUBSCRIPTION.getKey().equals(iapProduct.getProductType())) {
if (latestReceiptInfo == null || latestReceiptInfo.size() == 0) {
return;
}
for (Object item : latestReceiptInfo) {
if (item instanceof JSONObject) {
JSONObject jsonObjectItem = (JSONObject) item;
if (request.getTransactionId().equals(jsonObjectItem.getString("web_order_line_item_id"))) {
mapFieldAndSave(jsonObjectItem);
}
}
}
}
}
also did not match.
actually everytime the client request to server, the transaction id changed.
The transaction identifier used to be useful to make sure that a single receipt is not being hacked, duplicated, installed in many devices and used to get multiple IAPs. This protective system fell apart when Apple used the same transaction id for an original purchase, a repurchase-for-free and a restoreCompletedTransaction.
That's a good sentence to be put in a documentation. Will save many hours for some developers. from here。