四、<iOS IAP>内购之获取产品信息

首先,用户在购买产品时,应用程序从应用商店获取该产品的信息,把商店 界面提供给用户,然后让用户选择产品,如下图中第二阶段:


Snip20170516_4.png

一、获取产品 ID

在应用程序中出售的每个产品都有唯一的产品 ID。 应用程序使用 ID 到应用商店获取产品信息,比如价格,并在用户购买产品时,提交支付请求。 应用程序既可以从应用程序的文件中读取该产品 ID,也可以从应用服务器中获取产品 ID。表2-1 描述了这两种方法的区别:


Snip20170517_7.png

如果应用程序是固定的产品列表,比如内购来移除广告或开启功能,就 把列表整合到应用程序文件夹中。 如果产品 ID 不需要应用程序更新就可以做改变,比如支持额外关卡或角色的游戏,产品 ID 可以从应用的服务器获取产品 ID 列表。
在获取 iTunes Connect 中,现在没有运行机制可以为特殊的应用程序获得所有的产品列表。开发者需要负责管理应用程序 ID 列表并提供该信息给应用程序。如果开发者需要管理大量的产品 ID,建议使用 iTunes Connect 中用bulk XML 上传下载功能。

1、在应用程序 Bundle 中镶入产品 IDs

在应用束 Bundle 中包含特性列表文件,它包括了一个产品 ID 数组。如下:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
 "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<array>
    <string>com.example.level1</string>
    <string>com.example.level2</string>
    <string>com.example.rocket_car</string>
</array>
</plist>

要想从 plist 文件中获取产品 ID ,在应用 Bundle 中找到该文件并读取它,代码如下。

NSURL *url = [[NSBundle mainBundle] URLForResource:@"product_ids"
                                     withExtension:@"plist"];
NSArray *productIdentifiers = [NSArray arrayWithContentsOfURL:url];

2、从服务器获取产品 IDs

上传 JSON 文件到应用服务器,文件里带有产品 ID,内容如下:

[
    "com.example.level1",
    "com.example.level2",
    "com.example.rocket_car"
]

要想从服务器获取产品 ID,如列表2-1所示从应用服务器获得并读取该 JSON 文件。 考虑 JSON 文件的版本化,这样应用程序的未来版本就可以随时改变它的结构,而不需要打破应用程序的老版本。比如,你可以把使用老结构的产品命名为_v1.json, 把使用新结构的文件命名为_v2.json. 如果你的 JSON 文件比示例中的简单数组更复杂时,版本化方法更加有用。
Listing 2-1 从应用服务器获得并读取 JSON 文件

- (void)fetchProductIdentifiersFromURL:(NSURL *)url delegate:(id)delegate
{
    dispatch_queue_t global_queue =
           dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(global_queue, ^{
        NSError *err;
        NSData *jsonData = [NSData dataWithContentsOfURL:url
                                                  options:NULL
                                                    error:&err];
        if (!jsonData) { /* Handle the error */ }

        NSArray *productIdentifiers = [NSJSONSerialization
            JSONObjectWithData:jsonData options:NULL error:&err];
        if (!productIdentifiers) { /* Handle the error */ }

        dispatch_queue_t main_queue = dispatch_get_main_queue();
        dispatch_async(main_queue, ^{
           [delegate displayProducts:productIdentifiers]; // Custom method
        });
    });
}

更多关于使用 NSURLConnection 下载文件的信息,请看 “Using NSURLConnection” in URL Loading System Programming Guide.

为了确保应用程序保持响应,使用后台线程来下载 JSON 文件,并提取产品 ID 列表。 要想最小化数据转换,使用标准的HTTP缓存机制,比如 Last-Modified 和 If-Modified-Since 头。

二、在苹果商店中取回产品信息

为了确保用户只看到可买的产品,在显示应用的商店界面 之前,要在应用商店查询产品列表真实性。
在查询应用商店中,使用产品请求对象。首先,创建SKProductsRequest 对象,并用产品 ID 列表初始化它。 产品请求取回有效产品的信息,以及有效产品 ID 列表,然后调用它代理处理结果。 委托必须实现 SKProductsRequestDelegate 协议来处理从应用商店返回的响应。列表2-2简单代码实现。

// 自定义方法
- (void)validateProductIdentifiers:(NSArray *)productIdentifiers
{
    SKProductsRequest *productsRequest = [[SKProductsRequest alloc]
        initWithProductIdentifiers:[NSSet setWithArray:productIdentifiers]];
    productsRequest.delegate = self;
    [productsRequest start];
}

// SKProductsRequestDelegate 代理方法
- (void)productsRequest:(SKProductsRequest *)request
     didReceiveResponse:(SKProductsResponse *)response
{
    self.products = response.products;

    for (NSString *invalidIdentifier in response.invalidProductIdentifiers) {
        // Handle any invalid product identifiers.
    }

    [self displayStoreUI]; // 自定义展示界面方法
}

当用户购买产品时,需要给该产品对象提供支付请求,因此保留对象数组对产品的引用,该产品对象数组会被返回给委托。 如果应用出售的产品列表改变,或许想要创建自定义类来把引用和其它信息一起封装到产品对象中---比如, 图片或从服务器获取的描述文本。 支付请求在“Requesting Payment.” 中讨论。
返回的无效产品 ID 通常表明应用产品 ID 列表中发生了一个 error, 尽管它或许意味着该产品在 iTunes Connect 中没有被正确配置。良好日志和界面可以帮开发者更简单地解决该类型问题。 在产品构建中,应用需要优雅地失败,这意味着显示剩余的应用界面以及忽略无效产品。 在开发构建中,显示 error 来引起对该问题的关注。在产品和开发构建中,都使用 NSLog 来编写消息(message)来解决,这样就有无效识别码的记录。 如果应用从服务器获取列表,还要定义日志机制来让应用程序把无效识别码发送回服务器。

三、呈现应用商店界面

因为应用程序商店设计对内购销售有很重要的影响,因此界面设计值得投入时间和精力。 在应用内设计苹果商店界面。 商店 Kit 不会为苹果商店提供界面。 只有充分了解应用程序和据根程序去设计商店界面,才能以最佳方式展示商店产品。
当设计和实现应用商店的界面时,请考虑以下指南:
1.只在用户可以支付时显示商店。 调用 SKPaymentQueue 类 的canMakePayments 方法来确认用户是否可以支付。 如果用户不能支付(比如,父母限制), 可以显示 界面 表明一个商店不可用,或者完全忽略商店部分。
2.在应用程序中自然地呈现商店产品。 在应用 UI 找到最好的位置来显示应用商店 UI。 在用户可以使用它们的时候呈现产品---比如,当用户尝试使用高级功能时让用户解锁该功能。 特别关注用户第一次使用你的应用时的用户体验。
3.组织产品,这样探索就变得既简单又愉快。 如果应用只有少量的商店产品,你可以在屏幕上显示所有产品;否则就把产品分组或分类让用户可以容易找到。 带有大数量产品的应用,比如,漫画书或者有很多报道的杂志,制作可以让用户简单地发现它们想要购买的新产品会特别有用。 给产品不同的名字和视觉效果,明确地区分它们--如有需要,包括明确地比较。
4、向用户交流商店产品的价值。 用户想要准确地知道他们即将要买什么。 综合应用商店的信息,比如产品价格和描述,和服务器或应用束中的附加数据,比如,产品的图片或 demos。 让用户在购买之前以限制的方式体现产品。 举个例子,有一款游戏,让用户选择购买新赛车(race cars)可以让用户用新车试跑一圈。 又或者在绘图应用中,让用户购买额外的笔刷可以让用户用新笔刷在小便签上绘图,让它查看笔刷之间的区别。 这类的设计给用户提供体验产品的机会并说服它们购买。
5、使用应用商店返回的语言环境(locale)和货币清楚地显示价格。 确保能简单找到产品的价格并能简单地识别。 不要尝试在你的 UI 中把价格转换为一个不同的货币,即使用户的语言环境和价格的语言环境不一样。 想想看,一个在美国的用户因为它的单位和日期格式更喜欢英国的语言环境。 你的应用根据英国的语言环境显示它的 UI,但它任然需要用应用商店指定的语言环境显示产品信息。 为了尝试匹配余下界面的英国语言环境,把价格转换为英国英镑是不正确的。 用户在美国有一个应用商店账号,它用美元支付,因此会给你的应用提供一个以美元为单位的价格。还有,你得应用将以美元为单元显示价格。列表2-3 显示了如何通过使用产品的语言环境信息来正确设置价格单位。
表2-3 得到正确设置价格单位

NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
[numberFormatter setFormatterBehavior:NSNumberFormatterBehavior10_4];
[numberFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];
[numberFormatter setLocale:product.priceLocale];
NSString *formattedPrice = [numberFormatter stringFromNumber:product.price];

当用户选择好要购买的产品后,应用程序会连接到应用商店请求为该产品提供支付。

四、建议测试步骤

测试代码的每个部分来认证你已经正确地实现了该功能。

1、用测试账号登入应用商店

在 iTunes Connect 里创建一个测试账号,请看 iTunes Connect Developer Guide. 的“Creating Test User Accounts” 。在一个 iOS 开发设备中,在设置中退出应用商店。然后从 Xcode 构建和运行的应用。在一个 OS X 开发设备中,退出 Mac 应用商店。 然后在 Xcode 中构建应用并运行它。使用应用程序来完成内置购买。当提示登陆应用商店时,使用测试账号。 注意提示框中出现的[Environment: Sandbox]文字提示目前是连接到测试环境。如果[Environment: Sandbox] 没有出现,则表示使用的是产品环境。 确保应用运行在一个开发签署(development-signed)构建。签署的产品构建使用产品环境。

重要提示:不要用测试用户账号登陆产品环境,否则测试用户账号将无效不能再使用。
2、测试获取产品认证码列表

如果产品 ID 列表被整合在应用程序中,在它们加载后,在代码里设置一个断点,并认证包含了预期产品 ID 列表的 NSArray 对象。
如果产品 ID 是从服务器中获取的,使用网络浏览器如 Safari 或命令行工具如 curl 来手工获取 JSON 文件,并认证从服务器返回的数据,该数据包含了预期的产品 ID 列表。 同时还要认证得服务器正确地实现了标准 HTTP 缓存机制。

3、测试处理无效产品识别码

在产品 ID 列表中故意包含进一个无效识别码。(确保在测试成功后删除它),在产品构建中,验证应用程序显示了其余的商店UI,用户可以购买其他的产品。 在开发构建中,去验证应用程序中引起关注的问题。检查控制台日志并验证可以正确地识别无效产品识别码。

4、测试一个产品请求

使用测试好的产品 ID 列表,创建并递交SKProductsRequest 实例。 在代码中设置一个断点,检查有效和无效的产品识别码。 如果有无效产品识别码,检阅 iTunes Connect 中的产品并更正 JSON 文件或特性列表。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容