appstore 中審覈中,如果你app內賣的東西是個虛擬的產品,那麼你有可能被要求不能使用第三方支付工具,只能使用 IAP 應用內支付功能。
使用這個功能需要在apple 開發者後臺籤合同,設置銀行賬號,設置價格,這個就不講了,本篇主要講phonegap中整合IAP的代碼
/**
* 蘋果應用內支付
*/
(function (cordova) {
var define = cordova.define;
define("cordova/plugin/applepay", function (require, exports, module) {
var argscheck = require('cordova/argscheck'),
exec = require('cordova/exec');
exports.pay = function (productID,quantity, successCB, failCB) {
exec(successCB, failCB, "ApplePay", "pay", [productID,quantity]);
};
});
cordova.addConstructor(function () {
if (!window.plugins) {
window.plugins = {};
}
console.log("將插件注入cordovaapplepay...");
window.plugins.applepay = cordova.require("cordova/plugin/applepay");
console.log("applepay注入結果:" + typeof (window.plugins.applepay));
});
})(cordova);
<feature name="ApplePay">
<param name="ios-package" value="CDVApplePay" />
</feature>
#import <Cordova/CDV.h>
@interface CDVApplePay : CDVPlugin
@property (nonatomic,copy) NSString*callbackID;
//Instance Method
- (void)pay:(CDVInvokedUrlCommand*)command;
@end
#import "CDVApplePay.h"
#import "AppDelegate.h"
#import <StoreKit/StoreKit.h>
#import "MainViewController.h"
#import "Conts.h"
@implementation CDVApplePay
@synthesize callbackID;
- (void)pay:(CDVInvokedUrlCommand*)command {
if ([SKPaymentQueue canMakePayments]) {
NSString *produtid = [command.arguments objectAtIndex:0];
NSString* strQuantity =[command.arguments objectAtIndex:1];
buyQuantity = [strQuantity intValue];
MainViewController* view = [[MainViewController alloc] init];
[view getProductInfo:produtid];
// [[AppDelegate appDelegate] getProductInfo:produtid];
} else {
NSLog(@"失敗,用戶禁止應用內付費購買.");
NSString *js = [[NSString alloc]initWithFormat:@"yooshow.alert('%@')", @"您已禁止應用內購買,請先開啓" ];
[[AppDelegate appDelegate] runJS:js];
}
CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:@""];
[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
}
@end
MainViewController.m中添加
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
// 監聽購買結果
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
[[SKPaymentQueue defaultQueue] removeTransactionObserver:self];
}
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions {
for (SKPaymentTransaction *transaction in transactions)
{
switch (transaction.transactionState)
{
case SKPaymentTransactionStatePurchased://交易完成
NSLog(@"transactionIdentifier = %@", transaction.transactionIdentifier);
[self completeTransaction:transaction];
break;
case SKPaymentTransactionStateFailed://交易失敗
[self failedTransaction:transaction];
break;
case SKPaymentTransactionStateRestored://已經購買過該商品
[self restoreTransaction:transaction];
break;
case SKPaymentTransactionStatePurchasing: //商品添加進列表
NSLog(@"蘋果交易流水號開始交易transactionIdentifier = %@", transaction.transactionIdentifier);
NSLog(@"商品添加進列表此處我方服務器應創建訂單");
break;
default:
break;
}
}
}
- (void)completeTransaction:(SKPaymentTransaction *)transaction {
// Your application should implement these two methods.
NSString * productIdentifier = transaction.payment.productIdentifier;
NSString * receipt = [transaction.transactionReceipt base64Encoding];
NSLog(@"蘋果交易流水號完成交易transactionIdentifier = %@", transaction.transactionIdentifier);
if ([productIdentifier length] > 0) {
// 向自己的服務器驗證購買憑證
NSLog(@"購買成功應將修改我方服務器用戶數據憑證爲%@,產品信息%@",receipt,productIdentifier);
NSString *js = [[NSString alloc]initWithFormat:@"pay.applePayResult('%@','%@')", transaction.transactionIdentifier,receipt];
[[AppDelegate appDelegate] runJS:js];
}
// Remove the transaction from the payment queue.
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}
- (void)failedTransaction:(SKPaymentTransaction *)transaction {
if(transaction.error.code != SKErrorPaymentCancelled) {
NSLog(@"購買失敗");
} else {
NSLog(@"用戶取消交易");
}
NSString *js = [[NSString alloc]initWithFormat:@"$.ui.hideMask();" ];
[[AppDelegate appDelegate] runJS:js];
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}
- (void)restoreTransaction:(SKPaymentTransaction *)transaction {
NSLog(@"恢復購買");
NSString * productIdentifier = transaction.payment.productIdentifier;
NSString * receipt = [transaction.transactionReceipt base64Encoding];
if ([productIdentifier length] > 0) {
// 向自己的服務器驗證購買憑證
NSLog(@"恢復購買成功應將修改我方服務器用戶數據憑證爲%@,產品信息%@",receipt,productIdentifier);
}
// 對於已購商品,處理恢復購買的邏輯
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}
// 下面的ProductId應該是事先在itunesConnect中添加好的,已存在的付費項目。否則查詢會失敗。
- (void)getProductInfo:(NSString*) productID
{
NSSet * set = [NSSet setWithArray:@[productID]];
SKProductsRequest * request = [[SKProductsRequest alloc] initWithProductIdentifiers:set];
request.delegate = self;
[request start];
}
// 以上查詢的回調函數
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response {
NSArray *myProduct = response.products;
if (myProduct.count == 0) {
NSLog(@"無法獲取產品信息,購買失敗。");
NSString *js = [[NSString alloc]initWithFormat:@"$.ui.hideMask();" ];
[[AppDelegate appDelegate] runJS:js];
return;
}
// SKPayment * payment = [SKPayment paymentWithProduct:myProduct[0]];
// payment.quantity =buyQuantity;
SKMutablePayment * payment = [SKMutablePayment paymentWithProduct:myProduct[0]];
payment.quantity = buyQuantity;
[[SKPaymentQueue defaultQueue] addPayment:payment];
}
注意客戶端成功後的回調
最後服務端的驗證,服務端我用的是 C#
public bool ApplePayNotifyVerify(ApplePayParam param)
{
//驗證支付憑證
// 初始化通信處理類
try
{
//支付憑證不能被重複使用,檢查支付憑證是否已經被計入流水賬,如果被使用過,直接返回false, 未被使用過的纔可以驗證,並處理相關業務
var payment = PaymentService.Instance.GetList(p => p.AppleReceipt == param.AppleReceipt).FirstOrDefault();
if (payment == null)
{
var config = AppService.Instance.GetThirdPartyConfig();
System.Net.Http.HttpClient httpClient = new System.Net.Http.HttpClient();
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var receipt = "{\"receipt-data\":\"" + param.AppleReceipt + "\"}";
HttpContent content = new StringContent(receipt, Encoding.UTF8);
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
HttpResponseMessage response = httpClient.PostAsync(new Uri(config.ApplePayVerify), content).Result;
string result = response.Content.ReadAsStringAsync().Result.Replace(Environment.NewLine, string.Empty).Replace("\n", string.Empty);
var entity= JObject.Parse(result);
//AppleVerifyEntity entity = JsonConvert.DeserializeObject<AppleVerifyEntity>(result);
if (entity.Value<int>("status") == 0)
{
//成功之後修改訂單狀態,記帳,加花
OrderPaySuccessParam payParam = new OrderPaySuccessParam();
//訂單號
payParam.OrderNO = param.OrderNO;
//交易號
payParam.TradeNO = param.TradeNO;
//支付方式
payParam.PayMethod = PaymentMethodKind.Online;
//賣家收款賬戶
payParam.Account = config.ApplePayBankAccount;
//賣家收款賬戶銀行
payParam.Bank = config.ApplePayBankName;
//買家賬戶
payParam.PayAccount = "";
//買家收款賬戶銀行
payParam.PayBank = "";
//實際支付金額
var order = OrderService.Instance.GetList(o => o.OrderNO == param.OrderNO).FirstOrDefault();
//蘋果支付沒有返回支付金額,爲了避免後期驗證不通過,設置總金額爲實際訂單金額
payParam.TotalAmount = order.TotalAmount;
//支付時間
payParam.PayDate = DateTime.Now;
//支付工具類型
payParam.PayType = PayTypeKind.ApplePay;
//記錄支付憑證到流水賬
payParam.AppleReceipt = param.AppleReceipt;
OrderService.Instance.OrderPaySuccess(payParam);
return true;
}
else
{
return false;
}
}
else
{
throw new Exception("此支付憑證已被使用,請勿重複使用");
}
}
catch
{
return false;
}
}