当通过中央凹(https://github.com/j3k0/cordova-plugin-purchase/)使用Cordova应用购买插件时,交易对象仅包含一个"id"。
为什么它不像Android那样返回其余的细节?
我在 TestFlight 上与具有最新更新的实体 iPhone 5 上的沙盒用户进行了测试。
iOS 响应:
{
"id":"subscription_1",
"alias":"Subscription 20",
"type":"paid subscription",
"state":"approved",
"title":"Subscription",
"description":"Subscription",
"price":"$19.99",
"currency":null,
"loaded":true,
"canPurchase":false,
"owned":false,
"downloading":false,
"downloaded":false,
"transaction":{
"type":"ios-appstore",
"id":"1000000200491361"
},
"valid":true,
"transactions":[
"1000000200450592",
"1000000200450626",
"1000000200450699",
"1000000200450768",
"1000000200450968",
"1000000200451015",
"1000000200451978",
"1000000200452019",
"1000000200452040",
"1000000200452082",
"1000000200452130",
"1000000200452155",
"1000000200471605",
"1000000200471725",
"1000000200471771",
"1000000200491361"
]
}
安卓响应:
{
"id":"iap_id",
"alias":"Subscription 20",
"type":"paid subscription",
"state":"approved",
"title":"Standard Subscription",
"description":"Standard Subscription",
"price":"$19.99",
"currency":"USD",
"loaded":true,
"canPurchase":false,
"owned":false,
"downloading":false,
"downloaded":false,
"transaction":{
"type":"android-playstore",
"purchaseToken":"bhgenijimhhgenhadngmajnp.AO-J1OxzqrUBfYXMJinFFjbRSUhL6E7bcbfnp0uZpEWi_ziPiimWbFt4n7IjRMN_1_yrP5m0jVI5l0t9OzfhsfLGyoJ-5E1ey9KLewlEGEGBM_B4EbinjZ5tWTrl",
"receipt":"{"packageName":"com.package.first","productId":"iap_id","purchaseTime":1458232471621,"purchaseState":0,"purchaseToken":"bhgenijimhhgenhadngmajnp.AO-J1OxzqrUBfYXMJinFFjbRSUhL6E7bcbfnp0uZpEWi_ziPiimWbFt4n7IjRMN_1_yrP5m0jVI5l0t9OzfhsfLGyoJ-5E1ey9KLewlEGEGBM_B4EbinjZ5tWTrl","autoRenewing":false}",
"signature":"PmKBJWBlVcIg//lZuMaG0zIEQZMcPrJjPUipJ/m0Ccm69mAmh1nPNyy6/Du6FMDEWijEI9jpbnQjLz4/bWBuqjr2CCLImcBFnHkA+ZvslDlh5ZzjwxtC7kD6PwuOMlelqS82JhIRMv1ZwxIYdEA8+Y5XiIClmJ5qvtCcgjU8b2HXDy3lIj5GfWCXJkoE0BMVHLJZemTK4asB5VzxU2xbUrk6ugBmc5jJ0LdlDue12NhFI62edhZoMhOoWd7TJP+IadUb8fIUb4AGct3zI5ccM1pHrzwvUuU0VWxLUs5qr2zCNkz4kw=="
},
"valid":true
}
在 Android 上,包含交易详细信息的收据在购买后立即可用,因此它包含在"交易"字段中。
在 iOS 上,SDK 需要显式加载它。如果我是对的,这仅在配置收据验证时由插件完成。我想这就是你试图实现的目标。您应该尝试从您自己的"store.validator"方法中访问这些字段。
请参阅 https://github.com/j3k0/cordova-plugin-purchase/blob/master/doc/api.md#validator
好的,这就是我到目前为止所拥有的。 这适用于 iOS,我稍后将不得不返回并使用 Android 进行测试,但现在这有效,以下是 store.validator 方法中的产品对象:
var product = {
"id": "propicks",
"alias": "propicks",
"type": "consumable",
"state": "approved",
"title": "BEST BETS & More!",
"description": "BEST BETS, Pick Confidence, & ML Odds!",
"price": "$2.99",
"currency": "USD",
"loaded": true,
"canPurchase": false,
"owned": false,
"downloading": false,
"downloaded": false,
"transaction": {
"type": "ios-appstore",
"id": "1000000263098271",
"appStoreReceipt": "MIIT...",
"transactionReceipt": "ew..."
},
"valid": true,
"transactions": [ "1000000263098271" ]
}
经过一些测试,product.transaction.transactionReceipt似乎始终是唯一的收据,因此这是我正在与Apple验证的收据。 我使用的是耗材,因此订阅可能会有所不同。
这是我的store.validator方法:
store.validator = function(product, callback) {
app.kendoConsole.log('in STORE.VALIDATOR FUNCTION');
var myData = {
transactionReceipt: product.transaction.transactionReceipt,
purchaseType: product.transaction.type
};
$.ajax({
url: app.config.checkIosReceiptUrl,
data: myData,
type: "POST",
beforeSend: function() {
app.utils.showLoading(kendo.format("Verifying Receipt..."));
},
complete: function() {
app.utils.hideLoading();
},
error: function(jqXHR, textStatus, errorThrown) {
app.utils.hideLoading();
app.utils.handleAjaxErrors(jqXHR);
},
success: function(data) {
if (data.success) {
callback(true, {}); // success!
} else {
callback(false, "Validation Failed.");
}
}
});
好的,最后在服务器上,我的 C# 代码来 ping Apple,并确保收据在我的系统中始终是唯一的,不允许重播购买!
[HttpPost]
public JsonResult CheckIOS_Receipt( string transactionReceipt, string purchaseType )
{
bool isReceiptValid = false;
// first check my database to make sure this receipt is unique.
bool isNewPurchaseToken = InAppPurchaseBLL.IsNewPurchaseToken( transactionReceipt, purchaseType );
if ( isNewPurchaseToken ) {
var hasPassedReceiptValidationWithStore = InAppPurchaseBLL.IsAppleVerifiedPurchase( transactionReceipt );
if ( hasPassedReceiptValidationWithStore ) {
// at this point, I should save the purchase token.
isReceiptValid = true;
}
}
JsonResult data = Json( new { success = isReceiptValid } );
return data;
}
/// <summary>
/// Hit apple server and return true or false if token is legit.
/// </summary>
/// <param name="validPurchaseToken"></param>
/// <param name="isTest"></param>
public static bool IsAppleVerifiedPurchase( string validPurchaseToken, bool isTest = false ) {
bool isAppleVerified = false;
try {
var json = new JObject( new JProperty( "receipt-data", validPurchaseToken ) ).ToString();
ASCIIEncoding ascii = new ASCIIEncoding();
byte[] postBytes = Encoding.UTF8.GetBytes( json );
string appleURI;
if ( isTest ) {
appleURI = "https://sandbox.itunes.apple.com/verifyReceipt";
//appleURI = ConfigurationManager.AppSettings[ "Apple_Test_Receipt_Validation_URL" ];
}
else {
appleURI = "https://buy.itunes.apple.com/verifyReceipt";
//appleURI = ConfigurationManager.AppSettings[ "Apple_Production_Receipt_Validation_URL" ];
}
WebRequest request = HttpWebRequest.Create( appleURI );
request.Method = "POST";
request.ContentType = "application/json";
request.ContentLength = postBytes.Length;
using ( var stream = request.GetRequestStream() ) {
stream.Write( postBytes, 0, postBytes.Length );
stream.Flush();
}
var sendresponse = request.GetResponse();
string sendresponsetext = "";
using ( var streamReader = new StreamReader( sendresponse.GetResponseStream() ) ) {
sendresponsetext = streamReader.ReadToEnd().Trim();
}
if ( sendresponse.IsNotNullOrEmptyString() ) {
JObject jsonResponse = JObject.Parse( sendresponsetext );
int status = -1;
int.TryParse( jsonResponse[ "status" ].ToString(), out status );
/*
* When validating receipts on your server, your server needs to be able to handle a
* production-signed app getting its receipts from Apple’s test environment.
* The recommended approach is for your production server to always validate receipts against
* the production App Store first. If validation fails with the error code “Sandbox receipt used in production”,
* validate against the test environment instead.
* */
switch ( status ) {
case 21007:
/*
* This receipt is from the test environment, but it was sent to the production environment
* for verification. Send it to the test environment instead.
* */
// This means I'm testing on my device and still need to validate against the sandbox url.
return IsAppleVerifiedPurchase( validPurchaseToken, isTest: true );
case 21008:
/*
* This receipt is from the production environment, but it was sent to the test environment
* for verification. Send it to the production environment instead.
* */
// so I don't see this ever happening but if it does, resend it to the production envirnoment instead of the sandbox.
return IsAppleVerifiedPurchase( validPurchaseToken, isTest: false );
case 0:
// sweet success! the receipt is valid. Status should be either 0 or one of the error codes described here:
// https://developer.apple.com/library/content/releasenotes/General/ValidateAppStoreReceipt/Chapters/ValidateRemotely.html#//apple_ref/doc/uid/TP40010573-CH104-SW5
isAppleVerified = true;
break;
default:
isAppleVerified = false;
break;
}
}
}
catch ( Exception ex ) {
ex.Message.ToString();
}
return isAppleVerified;
}