在app里添加购买,并通过服务器端验证是否购买成功

本文介绍如何在iOS应用中集成InApp Purchase功能,包括添加Storekit框架、处理交易流程、请求产品信息及验证交易等关键步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一 有关如何在程序中加入In APP Purchase 的内容参考下面的连接
http://developer.apple.com/iphone/library/documentation/NetworkingInternet/Conceptual/StoreKitGuide/Introduction/Introduction.html#//apple_ref/doc/uid/TP40008267-CH1-SW1

 

http://www.cocoachina.com/appstore/market/2010/0504/1307.html
二 我的程序具体步骤
1 添加Storekit.Framework,编写自己的storeObsever,用于处理交易,代码如下,其中completeTransaction和failedTransaction两个函数是自定义的用来处理交易成功与失败其它的就都是SKPaymentTransactionObserver这个代理要求的。

#import <Foundation/Foundation.h> 

#import <StoreKit/StoreKit.h> 
 #import <StoreKit/SKPaymentTransaction.h> 
@interface MyStoreObserver : NSObject < SKPaymentTransactionObserver > {
}
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions; 
-(void) PurchasedTransaction: (SKPaymentTransaction *)transaction; 
- (void) completeTransaction: (SKPaymentTransaction *)transaction; 
- (void) failedTransaction: (SKPaymentTransaction *)transaction;
 -(void) paymentQueueRestoreCompletedTransactionsFinished: (SKPaymentTransaction *)transaction;
 -(void) paymentQueue:(SKPaymentQueue *) paymentQueue restoreCompletedTransactionsFailedWithError:(NSError *)error; 
@end 

- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions函数用来更新transactions的状态
 - (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions { 
 for (SKPaymentTransaction* transaction in transactions)  {  
switch (transaction.transactionState)  {  
case SKPaymentTransactionStatePurchased:  
[self completeTransaction:transaction];  
break;  
case SKPaymentTransactionStateFailed: 
 [self failedTransaction:transaction];  
break;  
case SKPaymentTransactionStateRestored: 
 break;  
default:  
break;  
}  


2 在程序中添加storeObsever,最好在applicationDidFinishLaunching中添加

MyStoreObserver *tempObserver = [[MyStoreObserver alloc] init];  
self.observer = tempObserver;  
[tempObserver release];
[[SKPaymentQueue defaultQueue] addTransactionObserver:self.observer]; 


3 发送付费请求,在相应的类中实现SKProductsRequestDelegate,别忘记定义自己产品的identifier

//请求产品信息 
 #define kMyFeatureIdentifier yourProductIdentifiers  (你自己的产品identifiers)
SKProductsRequest *request= [[SKProductsRequest alloc] initWithProductIdentifiers: 
 [NSSet setWithObject: kMyFeatureIdentifier]]; 
 request.delegate = self; 
[request start];  
代理方法相关代码,如果请求成功的话就可以发送付费请求  
#pragma mark request delegate
 //!收到产品的消息 
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response{  
SKPayment *payment = [SKPayment paymentWithProductIdentifier:kMyFeatureIdentifier]; 
 [[SKPaymentQueue defaultQueue] addPayment:payment]; 
[request autorelease];
  }
- (void)request:(SKRequest *)request didFailWithError:(NSError *)error{  
UIAlertView *alerView =  [[UIAlertView alloc] initWithTitle:@"Alert" message:[error localizedDescription]  delegate:nil c
ancelButtonTitle:NSLocalizedString(@"Close",nil)  otherButtonTitles:nil];  [alerView show]; [alerView release]; 
}


4  接下来就是Apple自己的付费相关处理了,需要做是就是点击按钮来确定付费
5 交易完成后需要向Apple验证这次交易是否成功,要不然没成功就把产品给别人的话,那就亏了,在1中可以看到当交易成功时会调用自定义的completeTransaction函数,在该函数中我们需要验证transactionReceipt 关于验证SKPaymentTransaction的transactionReceipt transactionReceipt是只有当SKPaymentTransaction完成时,即transactionState 被设置为SKPaymentTransactionStatePurchased 或 SKPaymentTransactionStateRestored时才被创建,因此只有这两种状态下能去验证transactionReceipt

原始思路及具体步骤如下: 

a 从SKPaymentTranscation的实例中将transactionReceipt转化为

NSString   NSString *temptransactionReceipt  = [[NSString alloc] initWithData:[mytransaction transactionReceipt] encoding:NSUTF8StringEncoding];
 如果用NSLog的方法将其写出来显示如下,里边有很多的‘+’ { "signature"= "AZNZdoggtjbU/wMqZ4SSd3lgkxbWr+/zcV7Oez4io7f5oPMliKlQzWW4vj+FLsVyhjyyuPyTSugJ6m4Hrp+CjdAptGZg4iWExoyE6stltg0EfD8Ezggjg5q04ws74pMZ/0aRgjedua8dCMMqR7C8ZjojfOYU6LrFiK7qbUUiV+inMIIDUzCCAjugAwIBAgIIZRSRTdlYBLUwDQYJKoZIhvcNAQEFBQAwfzELMAkGA1UEBhMCVVMxEzARBgNVBAoMCkFwcGxlIEluYy4xJjAkBgNVBAsMHUFwcGxlIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MTMwMQYDVQQDDCpBcHBsZSBpVHVuZXMgU3RvcmUgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDkwNjE1MjIwNTU2WhcNMTQwNjE0MjIwNTU2WjBkMSMwIQYDVQQDDBpQdXJjaGFzZVJlY2VpcHRDZXJ0aWZpY2F0ZTEbMBkGA1UECwwSQXBwbGUgaVR1bmVzIFN0b3JlMRMwEQYDVQQKDApBcHBsZSBJbmMuMQswCQYDVQQGEwJVUzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAytGMXZy3gitJ2JMKFojSDynC/9yYezyn9HBX+u3/3VcpWE2XhcgGKYqNBA1+AewOzrKO774OsokTu4qymEx10ph8UTmsZewB0ESMHBEjF7FN6/HccsQUYC3WagrHnT12HG2Ih0OAm/ZhpWzj0HS4m813LpIyo00sewMvMNL2hkcCAwEAAaNyMHAwDAYDVR0TAQH/BAIwADAfBgNVHSMEGDAWgBQ2HejinYLSARi1MmsO10MLkVhDOjAOBgNVHQ8BAf8EBAMCB4AwHQYDVR0OBBYEFKmDg/IZSMU+ElcIFMzNo36ZXyT1MBAGCiqGSIb3Y2QGBQEEAgUAMA0GCSqGSIb3DQEBBQUAA4IBAQARpJs+O2Y3gL8gHdASkrfZHFpwINd1VcB5VF5LkVpnFz63zylA/3cGIDG91b/d5NIwZjkVt4Bgvd62o/mCbzCsWiNfSKTJVFK1D78BDQoSO2oHTuQuz1BR7xzNHxQZ90zUS6ZX9SC8N3g3A1jEtAyDhZNB+CRBBXLwZdnBUeBsT9QLpjvTnekZcGTnU08zfCjGF3eBJEu9eP6WgexK1xMSp72kEOmYbn6yTi3D4YrcYx4Q3n/57VBP2en8qXWeP5oHDsLTGzLRsWdoB3VxJLrF2ivL8JS8zqC0qyac452pN6xunRuzyyfpaqzQL12BzFEe44xna2byektSbtquA5LNAAAAAA=="; "purchase-info" = "ewoJIml0ZW0taWQiID0gIjMzMDU5OTg4MCI7Cgkib3JpZ2luYWwtdHJhbnNhY3Rpb24taWQiID0gIjEwMDAwMDAwMDAwOTEyNTgiOwoJInB1cmNoYXNlLWRhdGUiID0gIjIwMDktMTAtMTQgMDY6MDY6NTQgRXRjL0dNVCI7CgkicHJvZHVjdC1pZCIgPSAiY29tLnNlbnNreS5jbmFtZXNpZ3B1cmNoYXNlY29uc3VtYWJsZSI7CgkidHJhbnNhY3Rpb24taWQiID0gIjEwMDAwMDAwMDAwOTEyNTgiOwoJInF1YW50aXR5IiA9ICIxIjsKCSJvcmlnaW5hbC1wdXJjaGFzZS1kYXRlIiA9ICIyMDA5LTEwLTE0IDA2OjA2OjU0IEV0Yy9HTVQiOwoJImJpZCIgPSAiY29tLnNlbnNreS5jc2lnbmF0dXJlYXBwIjsKCSJidnJzIiA9ICIxLjAiOwp9"; "pod" = "100"; "signing-status" = "0";}    

b 然后通过Post的方法将其提交给服务器,在这里只是将transactionReceipt传给服务器,验证由服务器完成。代码如下,    

NSString *requestStirng =[NSString stringWithFormat: @"receipt_data=%@",temptransactioReceipt]; 
requestStirng = [requestStirng stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; 

NSData *postData = [NSData dataWithBytes:[requestStirng UTF8String] length:[requestStirng length]]; 

NSMutableURLRequest *connectionRequest = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:[kURL   stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]]; 

[connectionRequest setHTTPMethod:@"POST"];  

[connectionRequest setTimeoutInterval:120.0]; 

[connectionRequest setCachePolicy:NSURLRequestUseProtocolCachePolicy]; 

[connectionRequest setHTTPBody:postData];  

出现的错误,服务器用传过去的receipt_data向Apple验证,通不过,但将用NSLog的方法在后台写出的temptransactionreceipt向Apple验证能通过  错误原因  对比发现通过URL传给服务器的字符串不能很好的完成urlEncode,在里边出现的+不能自动进行编码转化,因为在Objective-C 中不能将NSString 真正的实现URL encode , 

解决方法可参考下面的地址  

http://simonwoodside.com/weblog/2009/4/22/how_to_really_url_encode/ 

但当我用上面地址给出的方法进行编码后仍不能解决该问题,原因不明

 解决办法:

在将transactionReceipt转化成的NSString传给服务器之前先进行转化,将里边的+转换为%2B , 将步骤a中的代码改为 

 NSString *temptransactionReceipt  = [[NSString alloc] initWithData:[mytransaction transactionReceipt] encoding:NSUTF8StringEncoding]; 

 temptransactionReceipt =  [temptransactionReceipt stringByReplacingOccurrencesOfString:@"+" withString:@"%2B"];  

6 服务器端验证相关代码 其中XML为自定义的一个类,getHeader所做的工作就是把receipt数据Post给Apple然后得到返回的结果返回  

$url = "https://buy.itunes.apple.com/verifyReceipt";/ $receipt = json_encode(array("receipt-data" => base64_encode($receipt_data)));  

$response_json = $Xml->getHeader($url, $receipt);    

$response = json_decode($response_json['content'], true);

getHeader的代码如下  public function getHeader($url, $data)   

{

$ch = curl_init(); 

$timeout = 300; // set to zero for no timeout  

curl_setopt($ch, CURLOPT_URL, $url); 

 //       curl_setopt($ch, CURLOPT_ENCODING, 'gzip'); 

curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 1); //post到https 

curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);

curl_setopt($ch, CURLOPT_POST, true); 

curl_setopt($ch, CURLOPT_POSTFIELDS, $data);  

curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);  

curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);//跟随页面的跳转

//       curl_setopt($ch, CURLOPT_HEADER, true); 

curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout); 

$handles = curl_exec($ch); 

$header = curl_getinfo($ch);

curl_close($ch); 

$header['content'] = $handles; 

return $header; 

把自测试的例子地址:

http://www.cocoachina.com/bbs/job.php?action=download&aid=6127

<think>我们正在讨论UniApp中集成应用内购买(IAP)功能。由于UniApp是一个跨平台框架,而应用内购买主要涉及iOS和Android平台,因此需要分别考虑两个平台的配置。同时,UniApp本身可能不直接提供IAP模块,所以我们需要使用原生插件或第三方插件。 根据之前的对话,用户已经了解了iOS内购的二次验证注意事项,现在想知道如何在UniApp添加和配置内购项目。 步骤: 1. 选择插件:在UniApp中,通常使用原生插件来实现IAP功能。可以选择现成的第三方插件,如uni-app的官方插件市场中的插件,或者自己封装原生模块。 2. 配置各平台的内购项目:在App Store Connect和Google Play Console中分别创建内购商品。 3. 集成插件调用购买功能。 由于用户问题中提到了iOS内购,我们重点也会包括iOS,同时也会提及Android。 详细步骤: 一、创建内购商品(以iOS为例) 1. 登录App Store Connect,选择你的应用。 2. 进入“功能”下的“应用内购买项目”,点击“+”创建新的内购项目。 3. 选择类型(如消耗型、非消耗型等),填写商品ID(唯一标识)、价格等级、本地化信息等。 4. 提交等待审核(如果需要)。 二、在UniApp中集成IAP插件 假设我们使用一个名为`uni-iap`的插件(这仅作示例,实际应选择市场中的可用插件,如`uni-app`官方插件市场中的`iap`插件)。 1. 在插件市场搜索导入插件。 2. 配置原生模块: - iOS: 在Xcode中启用In-App Purchase功能,配置沙盒测试账号。 - Android: 在Google Play Console中创建应用内商品,在应用代码中配置公钥等。 3. 在UniApp项目中引入插件: ```javascript const iap = uni.requireNativePlugin('uni-iap'); ``` 4. 初始化IAP模块(通常在App启动时): ```javascript iap.init({ platform: 'apple', // 或 'google' products: ['product_id1', 'product_id2'] // 商品ID列表 }, result => { console.log('初始化结果:', result); }); ``` 5. 发起购买: ```javascript iap.purchase({ productId: 'product_id1' }, result => { if (result.code === 0) { // 购买成功,获取交易凭证(iOS为receipt,Android为purchaseToken等) // 将凭证发送到服务器进行二次验证 } else { // 购买失败 } }); ``` 6. 处理未完成的交易(特别是iOS): 在应用启动时,检查是否有未完成的交易,进行处理。 三、服务器二次验证(参考之前的注意事项) - iOS: 将receipt发送到服务器服务器Apple验证注意`receipt.in_app`数组包含所有未结束的交易。 - Android: 使用purchaseToken和packageName等向Google验证。 四、注意事项 - 跨平台处理:iOS和Android的IAP流程有差异,需要分别处理。 - 插件选择:确保插件支持最新的IAP规范,定期更新。 - 测试:务必在沙盒环境(iOS)和测试环境(Android)充分测试。 由于用户之前已经了解过二次验证的注意事项,这不再重复,但需要提醒在服务器端正确处理。 相关问题: 1. UniApp中如何选择适合的应用内购买插件? 2. 如何在Android平台配置应用内购买? 3. 应用内购买测试需要注意哪些事项?</think>### 在 UniApp 中集成应用内购买(IAP)的配置步骤 #### 一、前置条件 1. **开发者账户** - 苹果开发者账号([Apple Developer](https://developer.apple.com)) - Google Play 开发者账号([Google Play Console](https://play.google.com/console)) 2. **UniApp 环境** - 确保使用 HBuilderX 最新版 - 安装原生插件支持:`manifest.json` 中启用 `"usingComponents": true` #### 二、iOS 平台配置 1. **App Store Connect 设置** - 登录 [App Store Connect](https://appstoreconnect.apple.com) - 创建应用内购买项目: ```bash 产品类型:消耗型/非消耗型/订阅型 商品ID:唯一标识符(如 com.yourcompany.product1) ``` - 提交审核关联到应用[^1] 2. **Xcode 配置** - 在 `Capabilities` 中启用 `In-App Purchase` - 配置沙盒测试账号 3. **UniApp 集成插件** - 使用官方插件市场中的 `uni-iap` 插件 - 安装命令: ```bash npm install @dcloudio/uni-iap ``` #### 三、Android 平台配置 1. **Google Play 设置** - 在 [Google Play Console](https://play.google.com/console) 创建商品 - 配置商品ID 和定价(与 iOS 商品ID 建议保持一致) 2. **签名配置** - 获取应用签名 SHA-1(通过 Google Play 应用签名功能) - 配置到 UniApp 的 `build.gradle` #### 四、核心代码实现 ```javascript // 初始化 IAP import { initIAP, requestPurchase } from '@dcloudio/uni-iap'; // 1. 初始化(在 App.vue 的 onLaunch 中) initIAP({ provider: 'apple', // 或 'google' products: ['com.yourcompany.product1'] // 商品ID列表 }); // 2. 发起购买 async function buyProduct() { try { const result = await requestPurchase({ productId: 'com.yourcompany.product1' }); // 3. 服务器验证(关键步骤!) const validation = await uni.request({ url: 'https://your-server.com/validate-iap', method: 'POST', data: { receipt: result.receipt, // iOS 凭据 purchaseToken: result.purchaseToken // Android 凭据 } }); if (validation.data.success) { uni.showToast({ title: '购买成功' }); } } catch (err) { console.error('购买失败', err); } } ``` #### 五、服务器端验证要点 1. **iOS 验证** - 向 Apple 服务器发送 `receipt` 数据 - 注意解析 `receipt.in_app` 数组处理多笔交易[^2] - 验证 URL: `https://buy.itunes.apple.com/verifyReceipt`(沙盒环境使用沙盒URL) 2. **Android 验证** - 使用 Google Play Developer API 验证 `purchaseToken` - 需配置服务账号密钥(JSON 文件) #### 六、注意事项 1. **跨平台兼容** - 建议商品ID 保持 iOS/Android 一致 - 使用条件编译区分平台逻辑: ```javascript // #ifdef APP-IOS initIAP({ provider: 'apple' }); // #endif // #ifdef APP-ANDROID initIAP({ provider: 'google' }); // #endif ``` 2. **安全规范** - 永远在服务器端完成最终验证 - iOS 需处理订阅状态刷新(使用 `latest_receipt_info`) - 避免在客户端存储敏感交易数据 > **重要提示**:上架前必须通过平台沙盒测试,苹果对 IAP 审核严格,需确保符合 Guideline 3.1.1 规范[^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值