iOS7.0后,SKPayment的property transactionReceipt变成了DEPRECATED。

建议使用新接口来实现receipt的获取。

 [[[NSBundle mainBundle] appStoreReceiptURL] dataWithContentsOfURL:receiptURL];

如果使用了IAP,Apple官方的建议是使用下列代码来处理:

NSData *receipt = nil;

if (floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_6_1) {
    // Load resources for iOS 6.1 or earlier
    receipt = transaction.transactionReceipt;

} else {
    NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];
    receipt = [NSData dataWithContentsOfURL:receiptURL];
}

上面的代码很容易以为,新旧接口取得的receipt格式是一致的。其实不然。

在NtUniSdk里面,iOS官方渠道的易信和网易通行证使用了IAP,然后使用了上述Apple官方建议的代码,结果就是receipt格式不一致,计费验证不通过,把接入SDK的G3坑了一顿。

原来旧接口返回的receipt如下:

2014-07-24 15:53:51.284 [NetEase]iOSNtUniSdkFrameworkDemo[22831:4107] [NtUniSdk] IAP jsonResponse: {
	receipt =     {
    	bid = "com.netease.sdk.test";
    	bvrs = "1.0";
    	"item_id" = 892617314;
    	"original_purchase_date" = "2014-07-24 07:43:14 Etc/GMT";
    	"original_purchase_date_ms" = 1406187794660;
    	"original_purchase_date_pst" = "2014-07-24 00:43:14 America/Los_Angeles";
    	"original_transaction_id" = 1000000117879059;
    	"product_id" = "com.netease.sdk.test.item2";
    	"purchase_date" = "2014-07-24 07:43:14 Etc/GMT";
    	"purchase_date_ms" = 1406187794660;
    	"purchase_date_pst" = "2014-07-24 00:43:14 America/Los_Angeles";
    	quantity = 1;
    	"transaction_id" = 1000000117879059;
    	"unique_identifier" = 0000b0196818;
    	"unique_vendor_identifier" = "FEF4F2DB-D07D-4B96-8F22-592A4B9CBAE7";
	};
	status = 0;
}

而新接口返回的receipt:

2014-07-24 17:11:16.475 [NetEase]iOSNtUniSdkFrameworkDemo[185:748f] [NtUniSdk] IAP jsonResponse: {
	environment = Sandbox;
	receipt =     {
    	"adam_id" = 0;
    	"application_version" = "1.0";
    	"bundle_id" = "com.netease.sdk.test";
    	"download_id" = 0;
    	"in_app" =         (
                    	{
            	"is_trial_period" = false;
            	"original_purchase_date" = "2014-07-24 09:11:00 Etc/GMT";
            	"original_purchase_date_ms" = 1406193060000;
            	"original_purchase_date_pst" = "2014-07-24 02:11:00 America/Los_Angeles";
            	"original_transaction_id" = 1000000117894869;
            	"product_id" = "com.netease.sdk.test.item2";
            	"purchase_date" = "2014-07-24 09:11:01 Etc/GMT";
            	"purchase_date_ms" = 1406193061000;
            	"purchase_date_pst" = "2014-07-24 02:11:01 America/Los_Angeles";
            	quantity = 1;
            	"transaction_id" = 1000000117894869;
        	}
    	);
    	"original_application_version" = "1.0";
    	"original_purchase_date" = "2013-08-01 07:00:00 Etc/GMT";
    	"original_purchase_date_ms" = 1375340400000;
    	"original_purchase_date_pst" = "2013-08-01 00:00:00 America/Los_Angeles";
    	"receipt_type" = ProductionSandbox;
    	"request_date" = "2014-07-24 09:11:17 Etc/GMT";
    	"request_date_ms" = 1406193077021;
    	"request_date_pst" = "2014-07-24 02:11:17 America/Los_Angeles";
	};
	status = 0;
}

新旧receipt在验证API接口方面无变化,变化主要在于返回的jsonResponese格式。 新的jsonResponese格式官网文档如下:

Receipt Fields https://developer.apple.com/library/ios/releasenotes/General/ValidateAppStoreReceipt/Chapters/ReceiptFields.html#//apple_ref/doc/uid/TP40010573-CH106-SW1

下面是程序中实际输出jsonResponese的Log,值得注意的有receipt字段中的in_app字段可能包含多个transaction的receipt。 客户端APP中的新接口每次读取将读取出还没读取过的所有receipt,当上一次transaction完成后,但没有成功调用到读取receipt接口时,即将出现多条,如下第二条Log所示。

2014-07-24 16:06:52.077 [NetEase]iOSNtUniSdkFrameworkDemo[164:3e0b] [NtUniSdk] IAP jsonResponse: {
	environment = Sandbox;
	receipt =     {
    	"adam_id" = 0;
    	"application_version" = "1.0";
    	"bundle_id" = "com.netease.sdk.test";
    	"download_id" = 0;
    	"in_app" =         (
        	            {
            	"is_trial_period" = false;
            	"original_purchase_date" = "2014-06-23 06:59:55 Etc/GMT";
            	"original_purchase_date_ms" = 1403506795000;
            	"original_purchase_date_pst" = "2014-06-22 23:59:55 America/Los_Angeles";
            	"original_transaction_id" = 1000000114795007;
            	"product_id" = "com.netease.sdk.test.item1";
            	"purchase_date" = "2014-06-24 09:06:09 Etc/GMT";
            	"purchase_date_ms" = 1403600769000;
            	"purchase_date_pst" = "2014-06-24 02:06:09 America/Los_Angeles";
            	quantity = 1;
            	"transaction_id" = 1000000114795007;
        	},
            	        {
            	"is_trial_period" = false;
            	"original_purchase_date" = "2014-06-24 09:06:09 Etc/GMT";
            	"original_purchase_date_ms" = 1403600769000;
            	"original_purchase_date_pst" = "2014-06-24 02:06:09 America/Los_Angeles";
            	"original_transaction_id" = 1000000114938703;
            	"product_id" = "com.netease.sdk.test.item3";
            	"purchase_date" = "2014-06-24 09:06:09 Etc/GMT";
            	"purchase_date_ms" = 1403600769000;
            	"purchase_date_pst" = "2014-06-24 02:06:09 America/Los_Angeles";
            	quantity = 1;
            	"transaction_id" = 1000000114938703;
        	}
    	);
    	"original_application_version" = "1.0";
    	"original_purchase_date" = "2013-08-01 07:00:00 Etc/GMT";
    	"original_purchase_date_ms" = 1375340400000;
    	"original_purchase_date_pst" = "2013-08-01 00:00:00 America/Los_Angeles";
    	"receipt_type" = ProductionSandbox;
    	"request_date" = "2014-07-24 08:06:54 Etc/GMT";
    	"request_date_ms" = 1406189214105;
    	"request_date_pst" = "2014-07-24 01:06:54 America/Los_Angeles";
   		};
	status = 0;
}

Apple的IAP一直存在一个比较蛋疼的问题,在IAP的交易订单上没有填写额外信息的地方。由于存在网游的账号和AppStore支付账号两套系统,道具发放一直存在着可能在支付过程意外中断而导致漏洞的情况。iOS7.0在SKPayment中提供了一个applicationUsername属性用于填写用户信息,不过鉴于iOS7.0-的系统中没有该属性,在短时间内对这种意外情况改善也不大。