一、財務(wù)配置
image.png
登錄到蘋果哦itunsconnect后臺后圾另,可以到協(xié)議集乔、稅務(wù)和銀行業(yè)務(wù)
這里交給財務(wù)配置就行
二坡椒、itunes后臺商品配置
進入到我們的iTunes后臺后尤溜,在App Store
下面 有一個子欄目App 內(nèi)購買項目
這里點擊管理
我們就能看到我們進行商品配置的入口了
我們可以添加的商品類型
- Consumable 消耗品: 可以多次購買汗唱,適合游戲內(nèi)貨幣
- Non-Consumable 非消耗品: 購買一次哩罪,永久有效,適合解鎖永久功能;
- Non-Renewing Subscription 非續(xù)訂訂閱: 在固定時間段內(nèi)可用的內(nèi)容深碱,如vip
- Auto-Renewing Subscription 自動續(xù)費訂閱:到期會自動扣款的訂閱,適用按月的vip功咒;
詳細內(nèi)容請查看:https://developer.apple.com/support/app-store-connect/#//apple_ref/doc/uid/TP40013727-CH3-SW1
image.png
三力奋、客戶端集成(integration)
1幽七、支付流程
image.png
2、iOS- swift代碼
import StoreKit
class InAppPurchaseManager: NSObject,SKPaymentTransactionObserver, SKProductsRequestDelegate {
//登錄的時候調(diào)用
func addIAPObserver() -> Void {
SKPaymentQueue.default().remove(self)
SKPaymentQueue.default().add(self)
}
//登出的時候調(diào)用, 防止發(fā)貨到未知用戶
func removeIAPObserver() -> Void {
SKPaymentQueue.default().remove(self)
}
func addPayment(_ productId:String) {
let product = NSSet(array: [productId] as [AnyObject])
let request = SKProductsRequest(productIdentifiers: product as! Set<String>)
request.delegate = self
request.start()
}
func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
let avaliableProducts = response.products
guard let product = avaliableProducts.first else {
return
}
let mutablePayment = SKMutablePayment.init(product: product)
//發(fā)起購買請求
SKPaymentQueue.default().add(mutablePayment)
}
func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
for transaction in transactions {
switch transaction.transactionState {
case .purchased:
self.complete(transaction)
break
case .restored:
self.restored(transaction)
break
case .failed:
self.fail(transaction)
break
default:
//其他情況
break
}
}
}
//交易完成
func complete(_ transaction: SKPaymentTransaction) -> Void {
guard let receiptUrl = Bundle.main.appStoreReceiptURL, let receiveData:NSData = NSData(contentsOf: receiptUrl) else {
return
}
let receiptString = receiveData.base64EncodedString(options: .endLineWithLineFeed)
let transactionIdentifier = transaction.transactionIdentifier
//將transactionIdentifier & receiptString發(fā)送給服務(wù)器,去驗證票據(jù)的正確性
//todo
}
//交易失敗
func fail(_ transaction: SKPaymentTransaction) {
//todo
}
//交易restored
func restored(_ transaction:SKPaymentTransaction) {
//todo
}
//交易完成記得finish掉绩蜻,不然會出現(xiàn)卡單,無法進行下次支付
func finishTransactionWith(transactionId transctionId:String) {
let transactions = SKPaymentQueue.default().transactions
for transaction in transactions {
if transaction.transactionIdentifier == transctionId {
SKPaymentQueue.default().finishTransaction(transaction)
break
}
}
}
}
四办绝、簡單的服務(wù)器驗票邏輯(nodejs)
整個服務(wù)邏輯牽扯太多姚淆,我用nodejs整理出單純的驗票部分,簡單的校驗和借鑒是沒有問題的昔驱。
const https = require("https")
var postData = "客戶端傳過來receiptString";
var IAPVerifier = function(){};
IAPVerifier.verifyWithRetry = function(receipt, isBase64, cb) {
var encoded = null, receiptData = {};
if (isBase64) {
encoded = receipt;
} else {
encoded = new Buffer(receipt).toString('base64');
}
receiptData['receipt-data'] = encoded;
var options = this.requestOptions();
return this.verify(receiptData, options, (function(_this) {
return function(error, data) {
if (error) return cb(error);
if ((21007 === (data != null ? data.status : void 0)) && (_this.productionHost == _this.host)) {
// 指向沙盒測試環(huán)境再次驗證
options.host = 'sandbox.itunes.apple.com';
return _this.verify(receiptData, options, function(err, data) {
return cb(err, data);
});
} else {
return cb(error, data);
}
};
})(this));
};
/*
verify the receipt data
*/
IAPVerifier.verify = function(data, options, cb) {
var post_data = JSON.stringify(data);
var request = https.request(options, (function(_this) {
return function(response) {
var response_chunk = [];
response.on('data', function(data) {
if (response.statusCode !== 200) {
return cb(new Error("response.statusCode != 200"));
}
response_chunk.push(data);
});
return response.on('end', function() {
var responseData, totalData;
totalData = response_chunk.join('');
try {
responseData = JSON.parse(totalData);
} catch (_error) {
return cb(_error);
}
return cb(null, responseData);
});
};
})(this));
request.write(post_data);
request.end();
request.on('error', function (exp) {
console.log('problem with request: ' + exp.message);
});
};
IAPVerifier.requestOptions = function() {
return options = {
host: 'buy.itunes.apple.com',
port: 443,
path: '/verifyReceipt',
method: "POST",
rejectUnauthorized: false/*不加:返回證書不受信任CERT_UNTRUSTED*/
};
};
IAPVerifier.verifyWithRetry(postData, true, function (e, responseData) {
console.log("responseData:",JSON.stringify(responseData,null,'\t'));
//todo 驗證客戶端傳過來的transactionIdentifier纳本,是否存在于"in_app"中
});