22、iOS应用内购买与Twitter集成全解析

iOS应用内购买与Twitter集成全解析

应用内购买(In-App Purchase)

在开发iOS应用时,应用内购买是一种重要的盈利方式。以下将详细介绍应用内购买的各个关键步骤。

测试账户登录

不能直接在设置应用中使用测试账户登录。若直接登录,会被迫同意标准用户协议并被要求输入信用卡号。解决方法如下:
1. 使用设置应用退出当前的iTunes账户。
2. 退出账户后,在尝试购买时会提示登录或创建新账户,此时输入测试账户凭证。

注意 :若在主设备上测试,在进行真实购买或下载更新前,别忘了返回设置应用退出测试账户。

提交购买GUI截图

苹果要求在应用内购买获批销售前提交截图,以证明购买功能按预期工作。具体要求如下:
- 对于可解锁内容,需提供使用该物品的截图,如用户玩已购买关卡或使用已购买物品的截图。
- 若产品使用时不可见,苹果也接受显示物品已购买的商店截图。

注意 :在完成应用编写和调试并准备提交审核时才需提交截图。

开发者审批

在应用内购买准备上线前,需进行开发者审批。步骤如下:
1. 在网页浏览器中返回iTunes Connect,导航到应用审核页面的“管理应用内购买”部分。
2. 屏幕右上角会出现一个新的绿色按钮,点击后会提示提交产品的方式,有以下两种选择:
- 随二进制文件提交 :此选项将在下次上传二进制文件时启用应用内购买。
- 立即提交 :可向现有应用提交新产品。

注意 :若看到“随新二进制文件提交”选项,可能是因为应用的上一版本是在iOS 3.0支持应用内购买之前上传的。

收据验证

完成交易后,会收到包含在交易对象中的收据。苹果建议开发者验证收据的有效性,这可增加安全性,防止用户免费激活应用内购买。苹果提供了两个用于验证收据的服务器:
| 环境 | 服务器地址 |
| — | — |
| 沙盒环境 | sandbox.itunes.apple.com |
| 生产环境 | buy.itunes.apple.com |

以下是验证收据的代码示例:

-(BOOL)verifyReceipt:(SKPaymentTransaction *)transaction
{
    NSString *jsonObjectString = [self encode:(uint8_t *)transaction.transactionReceipt.bytes length:transaction.transactionReceipt.length];
    NSString *completeString = [NSString stringWithFormat:@"http://url-for-your-php?receipt=%@", jsonObjectString];
    NSURL *urlForValidation = [NSURL URLWithString:completeString];
    NSMutableURLRequest *validationRequest = [[NSMutableURLRequest alloc] initWithURL:urlForValidation];
    [validationRequest setHTTPMethod:@"GET"];
    NSData *responseData = [NSURLConnection sendSynchronousRequest:validationRequest returningResponse:nil error:nil];
    [validationRequest release];
    NSString *responseString = [[NSString alloc] initWithData:responseData encoding: NSUTF8StringEncoding];
    NSInteger response = [responseString integerValue];
    [responseString release];
    return (response == 0);
}

- (NSString *)encode:(const uint8_t *)input length:(NSInteger)length
{
    static char table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
    NSMutableData *data = [NSMutableData dataWithLength:((length + 2) / 3) * 4];
    uint8_t *output = (uint8_t *)data.mutableBytes;
    for (NSInteger i = 0; i < length; i += 3) {
        NSInteger value = 0;
        for (NSInteger j = i; j < (i + 3); j++) {
            value <<= 8;
            if (j < length) {
                value |= (0xFF & input[j]);
            }
        }
        NSInteger index = (i / 3) * 4;
        output[index + 0] = table[(value >> 18) & 0x3F];
        output[index + 1] = table[(value >> 12) & 0x3F];
        output[index + 2] = (i + 1) < length ? table[(value >> 6)  & 0x3F] : '=';
        output[index + 3] = (i + 2) < length ? table[(value >> 0)  & 0x3F] : '=';
    }
    return [[[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding] autorelease];
}

添加这两个方法到项目后,只需调用 verifyReceipt 方法并传入返回的交易对象,然后进行布尔测试以确定收据是否有效。

此外,还有一个简化的PHP脚本用于验证收据:

$receipt = json_encode(array("receipt-data" => $_GET["receipt"]));
// 注意:在生产环境中使用 "buy" 而非 "sandbox"
$url = "https://sandbox.itunes.apple.com/verifyReceipt";
$response_json = call-your-http-post-here($url, $receipt);
$response = json_decode($response_json);
// 保存数据
print $response->{'status'};
iOS 7本地收据验证

iOS 7增加了在设备上验证应用内购买收据的功能,无需通过第三方服务器。不过,服务器收据验证仍然可用,具体使用哪种方式取决于应用需求。苹果建议在调用 NSApplicationMain 函数之前,在应用的主函数中验证本地收据。步骤如下:
1. 使用 [[NSBundle mainBundle] appStoreReceiptURL]; 定位收据。
2. 若未找到收据,验证失败。
3. 找到收据后,需确保其已由苹果正确签名。苹果提供了使用OpenSSL验证收据签名的示例代码:

/* The PKCS #7 container (the receipt) and the output of the verification. */
BIO *b_p7;
PKCS7 *p7;
/* The Apple root certificate, as raw data and in its OpenSSL representation. */
BIO *b_x509;
X509 *Apple;
/* The root certificate for chain-of-trust verification. */
X509_STORE *store = X509_STORE_new();
/* ... Initialize both BIO variables using BIO_new_mem_buf() with a buffer and its size ... */

/* Initialize b_out as an output BIO to hold the receipt payload extracted during
 signature verification. */
BIO *b_out = BIO_new(BIO_s_mem());
/* Capture the content of the receipt file and populate the p7 variable with the
 PKCS #7 container. */
p7 = d2i_PKCS7_bio(b_p7, NULL);
/* ... Load the Apple root certificate into b_X509 ... */
/* Initialize b_x509 as an input BIO with a value of the Apple root certificate and load it into 
X509 data structure. Then add the Apple root certificate to the
 structure. */
Apple = d2i_X509_bio(b_x509, NULL);
X509_STORE_add_cert(store, Apple);
/* Verify the signature. If the verification is correct, b_out will contain the
 PKCS #7 payload and rc will be 1. */
int rc = PKCS7_verify(p7, NULL, store, NULL, b_out, 0);
/* For additional security, you may verify the fingerprint of the root certificate and verify the 
OIDs of the intermediate certificate and signing certificate. The OID in the certificate policies 
extension of the intermediate certificate is (1 2 840 113635 100 5 6 1), and the marker OID of the 
signing certificate is (1 2 840 113635 100 6 11 1). */
  1. 解析收据有效负载:
#include "Payload.h" /* This header file is generated by asn1c. */
/* The receipt payload and its size. */
void *pld = NULL;
size_t pld_sz;
/* Variables used to parse the payload. Both data types are declared in Payload.h. */
Payload_t *payload = NULL;
asn_dec_rval_t rval;
/* ... Load the payload from the receipt file into pld and set pld_sz to the payload size ... */
/* Parse the buffer using the decoder function generated by asn1c.  The payload
 variable will contain the receipt attributes. */
rval = asn_DEF_Payload.ber_decoder(NULL, &asn_DEF_Payload, (void **)&payload, pld,
  1. 提取收据属性:
/* Variables used to store the receipt attributes. */
OCTET_STRING_t *bundle_id = NULL;
OCTET_STRING_t *bundle_version = NULL;
OCTET_STRING_t *opaque = NULL;
OCTET_STRING_t *hash = NULL;
/* Iterate over the receipt attributes, saving the values needed to compute the
 GUID hash. */
size_t i;
for (i = 0; i < payload->list.count; i++) {
    ReceiptAttribute_t *entry;
    entry = payload->list.array[i];
    switch (entry->type) {
        case 2:
            bundle_id = &entry->value;
            break;
        case 3:
            bundle_version = &entry->value;
            break;
        case 4:
            opaque = &entry->value;
            break;
        case 5:
            hash = &entry->value;
            break;
    }
}
  1. 验证:
    • 比较收据的捆绑标识符与应用 info.plist 中的 CFBundleShortVersionStrong 值,若不匹配,验证失败。
    • 验证收据中的版本标识符字符串与 info.plist 中硬编码的值是否匹配,若不匹配,验证失败。
    • 检查收据的GUID与设备的GUID是否匹配,可使用 [[UIDevice currentDevice] identifierForVendor]; 获取设备的GUID,若不匹配,验证失败。

若收据存在且由苹果签名,捆绑标识符、版本和GUID的值都匹配,则收据和购买有效。

在UFOs应用中集成应用内购买

在UFOs应用中,有一个简单的产品,支付一次性费用可解锁不同颜色的飞船。实现步骤如下:
1. 用户购买产品后,在用户默认设置中存储一个键以记录该购买。
2. 为项目添加新的艺术资源。
3. 修改 viewDidLoad 方法以更改飞船图像:

-(void)viewDidLoad
{
    purchasedUpgrade = [[NSUserDefaults standardUserDefaults] boolForKey:@"shipPlusAvailable"];

    CGRect playerFrame = CGRectMake(100, 70, 80, 34);
    myPlayerImageView = [[UIImageView alloc] initWithFrame: playerFrame];
    myPlayerImageView.animationDuration = 0.75;
    myPlayerImageView.animationRepeatCount = 99999;
    NSArray *imageArray;

    if (purchasedUpgrade)
    {
        imageArray = [NSArray arrayWithObjects: [UIImage imageNamed: @"Ship1.png"], [UIImage imageNamed: @"Ship2.png"], nil];
    }
    else
    {
        imageArray = [NSArray arrayWithObjects: [UIImage imageNamed: @"Saucer1.png"], [UIImage imageNamed: @"Saucer2.png"], nil];
    }

    myPlayerImageView.animationImages = imageArray;
    [myPlayerImageView startAnimating];
    [self.view addSubview: myPlayerImageView];
}
Twitter集成

Twitter自2006年3月创建以来,已拥有超过5亿注册用户。苹果从iOS 5开始推动社交网络集成,首先支持的服务就是Twitter。以下介绍如何将Twitter集成到应用中。

UFOs应用中的Twitter集成

本部分不继续在现有UFOs源代码基础上开发,而是使用第3章的源代码并添加Twitter功能。目的是在游戏结束后将用户的分数发布到其Twitter时间线。

修改 exitAction: 函数,提示用户选择Twitter发布方法或退出返回主菜单:

-(IBAction)exitAction:(id)sender
{
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Tweet Score" message:@"Do you want to tweet your score on Twitter?" delegate:self cancelButtonTitle:@"Dismiss" otherButtonTitles:@"Tweet Composer", @"Custom Tweet", nil];

    [alert show];
    [alert release];
}

设置新的 alertView 委托方法来处理回调并确定所需操作:

- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
{
    // tweet composer
    if(buttonIndex == 1) {
    } else if(buttonIndex == 2) { // custom tweet
    } else if(buttonIndex == 0) {
        [[self navigationController] popViewControllerAnimated: YES];
        [self.gcManager reportScore:score forCategory:@"com.dragonforged.ufo.single"];
    }
}
iOS上的Twitter

自2011年引入以来,Twitter已成为iOS的重要组成部分。以下是iOS上Twitter的相关信息:
- 账户配置 :从iOS 6开始,Game Center在组合视图控制器中添加了分享应用的功能。Twitter账户通过设置应用进行配置,截至iOS 7,无法通过第三方应用为用户提供登录方法。
- 权限管理 :用户可通过设置应用配置多个Twitter账户,但权限是一次性授予所有账户的。每个应用首次请求Twitter功能时,必须请求访问用户Twitter账户的权限。用户可在设置应用的Twitter部分查看当前有权限的应用列表,并随时撤销特定应用的访问权限。
- 发布方法 :Social Framework提供了两种将项目发布到用户时间线的方法:
- Tweet Composer :使用内置的图形用户界面(GUI),类似于电子邮件编辑器。可设置预设消息、附件和URL,但用户在发送推文前可修改文本。
- 其他方法 :可根据具体需求进行开发。

通过以上步骤,开发者可以在iOS应用中实现应用内购买和Twitter集成,为用户提供更好的体验和更多的功能。

iOS应用内购买与Twitter集成全解析(下半部分)

深入探讨Twitter集成
Tweet Composer使用流程

Tweet Composer是一种方便快捷的推文发布方式,其使用流程如下:
1. 引入必要框架 :确保项目中引入了Social Framework。
2. 创建Tweet Composer实例 :在需要调用Tweet Composer的地方,创建相应的实例。示例代码如下:

#import <Social/Social.h>

if ([SLComposeViewController isAvailableForServiceType:SLServiceTypeTwitter]) {
    SLComposeViewController *tweetComposer = [SLComposeViewController composeViewControllerForServiceType:SLServiceTypeTwitter];
    [tweetComposer setInitialText:@"我在UFOs游戏中取得了高分,快来挑战我!"];
    [tweetComposer addURL:[NSURL URLWithString:@"https://example.com/ufosgame"]];
    [tweetComposer addImage:[UIImage imageNamed:@"game_screenshot.png"]];

    [self presentViewController:tweetComposer animated:YES completion:nil];
} else {
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"无法使用Twitter" message:@"请在设置中配置Twitter账户。" delegate:nil cancelButtonTitle:@"确定" otherButtonTitles:nil];
    [alert show];
    [alert release];
}
  1. 设置初始内容 :可以设置初始推文文本、添加URL和图片等。
  2. 展示Composer :使用 presentViewController 方法展示Tweet Composer,用户可以在其中修改内容并发送推文。
Custom Tweets实现思路

如果需要更灵活的推文发布方式,可以选择Custom Tweets。实现思路如下:
1. 获取授权 :使用 ACAccountStore 类获取用户的Twitter账户授权。示例代码如下:

#import <Accounts/Accounts.h>

ACAccountStore *accountStore = [[ACAccountStore alloc] init];
ACAccountType *accountType = [accountStore accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierTwitter];

[accountStore requestAccessToAccountsWithType:accountType options:nil completion:^(BOOL granted, NSError *error) {
    if (granted) {
        NSArray *accounts = [accountStore accountsWithAccountType:accountType];
        if (accounts.count > 0) {
            ACAccount *twitterAccount = [accounts objectAtIndex:0];
            // 进行后续操作
        }
    } else {
        // 处理授权失败情况
    }
}];
  1. 构建请求 :使用 NSURLRequest NSURLConnection 构建HTTP请求,向Twitter API发送推文。示例代码如下:
NSURL *url = [NSURL URLWithString:@"https://api.twitter.com/1.1/statuses/update.json"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setHTTPMethod:@"POST"];

NSString *tweetText = @"这是一条自定义推文,快来体验UFOs游戏!";
NSString *postData = [NSString stringWithFormat:@"status=%@", [tweetText stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]]];
[request setHTTPBody:[postData dataUsingEncoding:NSUTF8StringEncoding]];

[accountStore signRequest:request withAccount:twitterAccount completion:^(BOOL success, NSError *error) {
    if (success) {
        NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
        [connection start];
    } else {
        // 处理签名失败情况
    }
}];
  1. 处理响应 :实现 NSURLConnection 的代理方法,处理Twitter API的响应。
应用内购买与Twitter集成的整体流程

为了更清晰地展示应用内购买与Twitter集成的整体流程,以下是一个mermaid流程图:

graph LR
    classDef startend fill:#F5EBFF,stroke:#BE8FED,stroke-width:2px
    classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px
    classDef decision fill:#FFF6CC,stroke:#FFBC52,stroke-width:2px

    A([开始]):::startend --> B{是否进行应用内购买}:::decision
    B -->|是| C(进行购买流程):::process
    C --> D(验证收据):::process
    D --> E{收据是否有效}:::decision
    E -->|是| F(解锁购买内容):::process
    F --> G(游戏结束):::process
    G --> H{是否发布分数到Twitter}:::decision
    H -->|是| I{选择发布方式}:::decision
    I -->|Tweet Composer| J(使用Tweet Composer发布):::process
    I -->|Custom Tweets| K(使用Custom Tweets发布):::process
    B -->|否| G
    E -->|否| L(提示购买失败):::process
    H -->|否| M([结束]):::startend
    J --> M
    K --> M
    L --> G
总结

通过以上对应用内购买和Twitter集成的详细介绍,我们可以看到在iOS应用中实现这两个功能的具体步骤和方法。应用内购买为开发者提供了多种盈利途径,而Twitter集成则可以增加应用的社交性和用户参与度。

在应用内购买方面,从测试账户登录、提交购买截图、开发者审批到收据验证,每个步骤都有其重要性和具体操作方法。特别是iOS 7本地收据验证功能,为开发者提供了更安全、便捷的收据验证方式。

在Twitter集成方面,我们介绍了在UFOs应用中如何集成Twitter功能,包括修改 exitAction: 函数、设置委托方法,以及使用Tweet Composer和Custom Tweets两种发布方式。同时,还给出了具体的代码示例和实现思路。

开发者可以根据自己的应用需求,灵活运用这些技术,为用户提供更好的应用体验。希望本文对iOS开发者在应用内购买和Twitter集成方面有所帮助。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值