iOS 苹果内购详细步骤

2023-10-30

一、设置协议等相关

1.点击协议、税务和银行业务。
这里写图片描述

2.点击 Request Contracts 下面的 Request,一直点击直到主协议界面。
这里写图片描述

主协议界面
这里写图片描述
Contact info :联系人信息
Bank info :银行信息
Tax info :税务信息

3.点击 Contact Info 下面的Set Up,设置联系人信息,然后点击 Add New Contract,添加新的联系信息。
这里写图片描述

4.填写完整并保存。
这里写图片描述

5.选择联系人,因为我是独立开发,所以填写的自己的,如果你是多人开发,你可以添加多个联系人。

Senior Management:高级管理人员
Financial :财务
Technical :技术支持
Legal :法务
Marketing :市场推广

添加完成之后,对应选择好就行。
这里写图片描述

6.点击 Bank Info 下的 Set Up,然后点击 Add Bank Account 添加银行账号。
这里写图片描述

点击 Select One,选择 China ,点击 next。
这里写图片描述

填写 CNAPS Code,点击 next。
这里写图片描述

CNAPS Code:中国现代化支付系统代码,又叫做联行号。可以从网上查询,也可以直接点击Look up CNAPS Code进行查询,再不济,也可以直接打电话咨询相应银行客服。

点击 next,核对一下,继续 next。

填写银行卡相关信息,点击 next。(持卡人姓名,如张三(Zhang San))
这里写图片描述

确认一下,点击 save 保存。
这里写图片描述

选择对应的银行卡,点击 save。
这里写图片描述

7.点击 Tax Info 下面的 Set Up,设置税务信息。

税务分三种:
U.S Tax Forms : 美国税务
Australia Tax Forms:澳大利亚税务
Canada Tax Forms : 加拿大税务

我们选择美国税务,点击 Done。
这里写图片描述

如果没有就选择 NO,点击 Submit。
这里写图片描述

如果没有就选择 NO。
这里写图片描述

填写完整,点击 Submit。
这里写图片描述

这里写图片描述

核对信息无误后提交,状态显示 Processing 表示成功。
这里写图片描述

二、创建项目的内购条目

1.进入 APP,点击功能。
这里写图片描述

根据情况选择,我选择的第一个。
这里写图片描述

填写内购项目信息,点击存储。
这里写图片描述

下面这些信息也要填完整,否则会提示元数据丢失(坑)。
这里写图片描述

注意:你 App 有几个内购级别就需要依次创建几个条目。
这里写图片描述

三、添加沙盒测试账号

1.点击用户和职能
这里写图片描述

2.点击沙盒技术测试员
这里写图片描述

3.点击 “+” 添加测试员,邮箱和密码用于支付的时候登陆 Apple ID。
这里写图片描述

四、代码集成

#import "ApplePayVC.h"
//导入
#import <StoreKit/StoreKit.h>

//遵循代理
@interface ApplePayVC ()
<
SKPaymentTransactionObserver,
SKProductsRequestDelegate
>

//支付按钮
@property (nonatomic, strong) UIButton *payBtn;

@end

@implementation ApplePayVC

- (void)viewDidLoad
{
    [super viewDidLoad];

    [self setupPayBtn];

    //设置支付服务
    [[SKPaymentQueue defaultQueue] addTransactionObserver:self];
}

#pragma mark - UI
- (void)setupPayBtn
{
    _payBtn = [UIButton buttonWithType:UIButtonTypeCustom];
    _payBtn.frame = CGRectMake(100, 100, 100, 100);
    _payBtn.backgroundColor = [UIColor redColor];
    [_payBtn setTitle:@"支付" forState:UIControlStateNormal];
    [_payBtn setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
    _payBtn.titleLabel.font = [UIFont systemFontOfSize:15.0];
    [_payBtn addTarget:self action:@selector(payBtnAction) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:_payBtn];
}

#pragma mark - BtnAction
- (void)payBtnAction
{
    //是否允许内购
    if ([SKPaymentQueue canMakePayments]) {
        NSLog(@"用户允许内购");

        //bundleid+xxx 就是你添加内购条目设置的产品ID
        NSArray *product = [[NSArray alloc] initWithObjects:@"bundleid+xxx",nil];
        NSSet *nsset = [NSSet setWithArray:product];

        //初始化请求
        SKProductsRequest *request = [[SKProductsRequest alloc] initWithProductIdentifiers:nsset];
        request.delegate = self;

        //开始请求
        [request start];

    }else{
        NSLog(@"用户不允许内购");
    }

}

#pragma mark - SKProductsRequestDelegate
//接收到产品的返回信息,然后用返回的商品信息进行发起购买请求
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response NS_AVAILABLE_IOS(3_0)
{
    NSArray *product = response.products;

    //如果服务器没有产品
    if([product count] == 0){
        NSLog(@"没有该商品");
        return;
    }

    SKProduct *requestProduct = nil;
    for (SKProduct *pro in product) {

        NSLog(@"%@", [pro description]);
        NSLog(@"%@", [pro localizedTitle]);
        NSLog(@"%@", [pro localizedDescription]);
        NSLog(@"%@", [pro price]);
        NSLog(@"%@", [pro productIdentifier]);

        //如果后台消费条目的ID与我这里需要请求的一样(用于确保订单的正确性)
        if([pro.productIdentifier isEqualToString:@"bundleid+xxx"]){
            requestProduct = pro;
        }
    }

    //发送购买请求
    SKMutablePayment *payment = [SKMutablePayment paymentWithProduct:requestProduct];
        payment.applicationUsername = userId;//可以是userId,也可以是订单id,跟你自己需要而定
    [[SKPaymentQueue defaultQueue] addPayment:payment];
}

#pragma mark - SKRequestDelegate
//请求失败
- (void)request:(SKRequest *)request didFailWithError:(NSError *)error
{
    NSLog(@"error:%@", error);
}

//请求结束
- (void)requestDidFinish:(SKRequest *)request
{
    NSLog(@"请求结束");
}

#pragma mark - SKPaymentTransactionObserver
//监听购买结果
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
{
    for(SKPaymentTransaction *tran in transactions){
        switch (tran.transactionState) {
            case SKPaymentTransactionStatePurchased:
                NSLog(@"交易完成");
                [self completeTransaction:tran];

                break;
            case SKPaymentTransactionStatePurchasing:
                NSLog(@"商品添加进列表");

                break;
            case SKPaymentTransactionStateRestored:
                NSLog(@"已经购买过商品");
//                [[SKPaymentQueue defaultQueue] finishTransaction:tran]; 消耗型商品不用写

                break;
            case SKPaymentTransactionStateFailed:
                NSLog(@"交易失败");
                [[SKPaymentQueue defaultQueue] finishTransaction:tran];

                break;
            default:
                break;
        }
    }
}

//交易结束,当交易结束后还要去appstore上验证支付信息是否都正确,只有所有都正确后,我们就可以给用户方法我们的虚拟物品了。
- (void)completeTransaction:(SKPaymentTransaction *)transaction
{
    // 验证凭据,获取到苹果返回的交易凭据
    // appStoreReceiptURL iOS7.0增加的,购买交易完成后,会将凭据存放在该地址
    NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];
    // 从沙盒中获取到购买凭据
    NSData *receiptData = [NSData dataWithContentsOfURL:receiptURL];
    //发送POST请求,对购买凭据进行验证
    //测试验证地址:https://sandbox.itunes.apple.com/verifyReceipt
    //正式验证地址:https://buy.itunes.apple.com/verifyReceipt
    NSURL *url = [NSURL URLWithString:AppStore_URL];
    NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:15.0f];
    urlRequest.HTTPMethod = @"POST";
    NSString *encodeStr = [receiptData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];
    _receipt = encodeStr;
    NSString *payload = [NSString stringWithFormat:@"{\"receipt-data\" : \"%@\"}", encodeStr];
    NSData *payloadData = [payload dataUsingEncoding:NSUTF8StringEncoding];
    urlRequest.HTTPBody = payloadData;

    NSData *result = [NSURLConnection sendSynchronousRequest:urlRequest returningResponse:nil error:nil];

    if (result == nil) {
        NSLog(@"验证失败");
        return;
    }

    NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:result options:NSJSONReadingAllowFragments error:nil];
    NSLog(@"请求成功后的数据:%@",dic);
    //这里可以通过判断 state == 0 验证凭据成功,然后进入自己服务器二次验证,,也可以直接进行服务器逻辑的判断。
    //本地服务器验证成功之后别忘了 [[SKPaymentQueue defaultQueue] finishTransaction: transaction];

    NSString *productId = transaction.payment.productIdentifier;
    NSString *applicationUsername = transaction.payment.applicationUsername;

    NSLog(@"applicationUsername++++%@",applicationUsername);
    NSLog(@"payment.productIdentifier++++%@",productId);

    if (dic != nil) {
        userId = applicationUsername;
        //服务器二次验证
        [self vertifyApplePayRequestWith:transaction];
    }
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}


注意:
1.内购必须用真机测试
2.测试时必须退出App Store自己的Apple ID,登录沙盒的测试Apple ID

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

iOS 苹果内购详细步骤 的相关文章

  • App Store 审核指南(中文版)

    App Store 审核指南 中文版 时间 2010 09 17 12 51 苹果对开发者提交的应用的审核之严格是出了名的 了解苹果的审核标准对于开发者防止应用被拒有着十分重要的意义 几天前苹果官方公布了 App Store 审核指南 后经
  • iOS开发—RunLoop详解

    随着oc语言不断迭代 苹果的API也是逐步完善 RunLoop在实际开发中应用的越来越少 但是在面试中 假如面试官问你RunLoop的相关知识了解 那就相当于面试官在问你从事iOS开发工作的真实年限问题 那么下面我们就详细了解一下RunLo
  • iOS应用添加第三方支付

    最简单明了的教程还是官方文档 以下是我给应用添加支付功能 记录下 1 微信支付 官方文档 https pay weixin qq com wiki doc api app php chapter 8 5 假设你的应用在微信开放平台已经创建
  • ios导航栏透明

    功能需求 根新浪微博个人主页类似 下拉拉伸放大图片下拉刷新 前面文章已解决 向上滑动的时候 导航栏的透明度逐渐增加 最后变成不透明的 当然说起来感觉其实没什么 不就是滑动改变透明度吗 但是做起来完全不是你想象的那样 首先解决透明度的问题 让
  • IOS 启动画面和图标设置(适配IOS7 and Xcode5)

    关于IOS程序设置启动画面以及图标的设备目前主要为 IPhone设备 和IPad设备 IPhone启动画面以及图标的设置 目前IPhone的分辨率为 320X480 640X960 640X1136 Default png 320X480
  • 2022最新苹果开发者账号注册、付款流程图解【图文并茂】

    更新日期 2022 07 22 每年续费就有一个坑 文章末尾已注明 1 申请一个邮箱 用于注册苹果开发者账号 我的邮箱 密码 2 注册开发者账号 1 注册官网 官网地址 Apple Developer Program Apple Devel
  • 编译错误:”Too many arguments to function call, expected 0, have 2 ”的解决

    在进行大规模工程开发的时候 或者是对原有工程结构进行调整 会出现很多编译问题 其中 Too many arguments to function call expected 0 have 2 是比较常见的一种 这个编译报错在Xcode8上比
  • 非对称加密算法--RSA加密原理详解

    密码学是在编码与破译的斗争实践中逐步发展起来的 并随着先进科学技术的应用 已成为一门综合性的尖端技术科学 密码学发展史 在说RSA加密算法之前 先说下密码学的发展史 其实密码学的诞生 就是为了运用在战场 在公元前 战争之中出现了秘密书信 在
  • iOS开发之第三方支付支付宝支付教程,史上最新最全第三方支付宝支付方式实现、支付宝集成教程,支付宝实现流程

    本章项目demo https github com zhonggaorong alipayDemo 支付宝支付大致流程为 1 公司与支付宝进行签约 获得商户ID partner 和账号ID seller 和私钥 privateKey 开发中
  • ios10.3之CoreData的详细教程

    首先如果要使用CoreData可以选择在初创项目时选择添加coredata 也可以选择自己添加coredata文件 系统添加coredata后会在Appdelegate类中自动添加一个persistentContainer属性 和一个sav
  • 地球坐标,火星坐标,百度坐标转换

    标准地球坐标即GPS设备获得的坐标 该坐标需要经过国家测绘局进行加密后形成火星坐标 WGS 84 我们用的google坐标和高德地图坐标也就是火星坐标 百度地图 在火星坐标的基础上再进行一次加密 形成了百度地图上的坐标 因此 直接将标准地球
  • iOS 15 适配踩坑:NavigationBar、UITabBar失效问题

    苹果前两天推出了iOS 15 秋天都等不及 相关链接 ios 15 0 适配问题 NavigationBar和UITabBar失效问题 Xcode 13 beta版 iOS 15 beta 3的系统 除了客户提出的问题 自己还发现了两处UI
  • Reachability(判断网络是否连接)

    类似于一个网络状况的探针 NSNotificationCenter defaultCenter addObserver self selector selector reachabilityChanged name kReachabilit
  • xxx.app已损坏,打不开。 您应该将它移到废纸篓。

    Mac最新的系统打开网上下载的应用程序时 会提示 xxx app已损坏 打不开 您应该将它移到废纸篓 解决方式 1 系统偏好设置 gt 安全性与隐私 gt 修改为任何来源 2 serria里面没有 任何来源 这一项 需要打开终端执行sudo
  • APP开发如何批量生成不同尺寸的图标?

    在我们开发APP的时候 我们使用到大量的不同尺寸的APPLogo的图片 如下图 通常 我们的做法是和设计师沟通 让他们切出这儿所以的图片 然后我们一个一个图片放在对应的位置 这样处理的话 我们比较容易出错 比如说 图片的格式 苹果对图片的格
  • Xcode8不能在iOS7上调试,Could not find Developer Disk Image的解决方法

    升级完Xcode8之后 默认情况下 是无法进行iOS7的调试的 因为Xcode8里面不再游iOS7的镜像文件 所以会提示 Could not find Developer Disk Image 解决方法如下 打开finder 应用程序 Xc
  • Xcode5.1离线下载安装及使用iOS5模拟器进行开发调试的方法

    Xcode5 1默认不支持iOS5版本的模拟器开发调试 在OS X Mavericks 10 9 x 下默认只能支持iOS6 1及以上版本的模拟器 在OS X Mountain Lion 10 8 x 下默认只能支持iOS6 0及以上版本的
  • 如何获取iPhone手机的UUID

    方法一 通过Windows下的iTunes 1 数据线连接iPhone手机 在Windows下打开iTunes 在 iPhone 管理界面下zhi点击 序列号 查看自己的 UUID 标识符 2 此dao时点击菜单 编辑 gt 复制 3 新建
  • iOS weak关键字实现原理

    在iOS中 使用weak关键字能够对内存对象进行弱引用 基于这个特性 使用weak关键字能够解决许多问题 例如delegate中对象的循环持有问题 Block对对象的强引用导致的对象无法及时释放问题 为何weak关键字能够实现对内存对象的弱
  • iOS代码混淆初探

    iOS代码混淆初探 在没有对应用的代码做过特殊处理的情况下 一般应用的代码中的类名和方法都是明文的 在逆向分析中 通过class dump获取MachO可执行文件中的所有类 定义的方法和属性 就能很快的从名字入手猜到这个方法是做什么用的 所

随机推荐

  • 错题本 - 机器学习

    下面关于支持向量机 SVM 的描述错误的是 A 是一种监督式学习的方法 B 可用于多分类的问题 C 是一种生成式模型 D 支持非线性的核函数 答案 C 解析 SVM是判别式模型 SVM 支持向量机 SVM 是一类按监督学习方式对数据进行二元
  • File,FileInputStream,FileReader,InputStreamReader,BufferReader 的区别使用

    File 类介绍 File 类封装了对用户机器的文件系统进行操作的功能 例如 可以用 File 类获得文件上次修改的时间 移动 或者对文件进行删除 重命名 换句话说 流类关注的是文件内容 而 File 类关注的是文件在磁盘上的存储 主要方法
  • 使用jsp获取页面的访问ip地址并统计访问量

    jsp获取页面的访问ip地址并统计访问量 考虑到ip地址是唯一不重复的 可以使用set集合来放置ip 然后用set size 得到ip的数量 话不多说 代码在下面
  • 毕业项目SSM框架配置文件之web.xml

  • 【AIGC】AI-Agents最新成果-斯坦福AI小镇源码解读

    写在前面的话 今年年初斯坦福和谷歌的研究人员创建了一个类似于 模拟人生 的微型 RPG 虚拟世界 其中 25 个角色由 GPT 和自定义代码控制 并在arxiv上提交了论文版本 引起了对AIGC 游戏的广泛讨论 8月 该项目在GitHub上
  • TensorFlow2 Fashion-MNIST图像分类(一)

    1 数据集介绍 FashionMNIST 是一个替代 MNIST 手写数字集的图像数据集 它是由 Zalando 一家德国的时尚科技公司 旗下的研究部门提供 其涵盖了来自 10 种类别的共 7 万个不同商品的正面图片 FashionMNIS
  • linux网卡驱动更换,Ubuntu更换网卡驱动

    由于Ubuntu自带的网卡驱动并不一定十分适合自己电脑的网卡 可能会出现插入网线后响应慢的情况 所以可以手动更换Ubuntu的网卡驱动 此处更换以我自己电脑上网卡为例 我的网卡是Realtek生产的 以下是具体过程 1 ifconfig a
  • 一条十几秒的Tik Tok视频月变现9w,2022年还得是短视频来钱快

    大家好 我是项柚 95后社畜一枚 之前辛辛苦苦给老板打一个月苦工 还没我现在做短视频带来的收益高 仅代表个人收益 从一个不怎么冲浪连抖音都懒得刷的门外汉 短短一个多月 一次性还清了自己的银行卡贷款 4个月攒出来某市中心30w房子的首付 原来
  • python中chr函数是什么意思_ord函数和chr函数

    ord函数 order 返回一个字符对应的unicode编码 而chr函数 char 正好反过来 它返回一个unicode编码对应的字符 他们都是python内置函数 为什么是unicode 因为unicode长度统一 都是2个byte 非
  • F - Shifting String(置换的阶+思维)

    前置知识 轮换求置换的阶 例如 由1 2 3 4 5 变为 1 3 2 5 4可以写出其两个转换 1 3 2 4 5 在同一个转换中的数字经过循环可以回到他们对应的原位置 置换的阶即为所有轮换阶数的最小公倍数 lcm 一组数据的最小公倍数
  • Python opencv学习-2读取视频,存视频,设置视频大小

    test2 各种通道读取视频 摄像头 url 视频文件 存视频 设置视频大小等 import numpy as np import cv2 视频来源为摄像头 cap cv2 VideoCapture 0 视频来源为视频文件 cap cv2
  • 技术详解 阿里云AIoT物模型支撑设备规模已超亿级——设备管理运维类

    物模型技术对于物联网企业来说是一项非常重要的技术 因为要实现万物互联 必须要有物模型体系沉淀 才能够让各种硬件产品实现真正的智能化连接 对于阿里云AIoT来说 物模型技术早已完成了多年的沉淀 目前 阿里云AIoT物模型技术已成为行业的引领者
  • 前端h5与 android/ios 交互传参

    介绍 前端 与 Android iOS 交互的代码 双方要约定一个公用的方法 1 与Android交互 前端 调用 Android 的方法 这里将约定的方法名为 HtmlToAndroid window android HtmlToAndr
  • 随笔:@Async注解

    记录 Async使用方法以及遇到的问题 1 在启动类使用 EnableAsync SpringBootApplication EnableAsync public class AsyncApplication public static v
  • 虚拟机安装宝塔后,站点域名无法访问

    1 虚拟机右键 设置 2 网络适配器 选择桥接模式 桥接模式支持别人访问 nat模式仅支持自己访问 3 重启虚拟机 或者重启网卡 4 ifconfig指令获取下对外可以访问的IP 如图中 172 16 5 114 5 宝塔配置一下域名 域名
  • Pytorch BrokenPipeError: [Errno 32] Broken pipe

    今天运行Pytorch出现Broken pipe错误 通过修改torch utils data DataLoader 函数中的 num workers 参数 解决 可能是因为windows对多线程的支持不是很好的原因吧 出错 修改后 默认n
  • JNDIExploit-1.2-SNAPSHOT.jar工具在log4j漏洞复现中的使用

    1 首先搭建log4j靶场 2 开启服务 Windows攻击端执行以下命令 java jar JNDIExploit 1 2 SNAPSHOT jar l 8888 p 9999 i 127 0 0 1 再开一个cmd可以看下能用什么pay
  • 谈debug版本可以正常运行,而在release下运行出错之原因及避免类似情况发生

    以前在学校时 经常碰到这样的情况 程序在Debug模式下运行的好好的 可是一换到Release模式下 就出错 实在很郁闷 而当时还经常天真的以为是工程文件有问题 也没有去分析原因 直到上次有位同事也碰到类似的问题 于是想拿那个程序来开开刀
  • 微信Hook逆向-获取登录二维码

    文章目录 前言 一 打开Pc微信 切换到二维码界面 二 解析当前二维码内容 三 利用Cheat Enginer软件扫描二维码解析文本 四 寻找静态偏移 五 代码获取二维码网址 前言 微信二维码可以Hook获取 也可以通过找到静态偏移的方式读
  • iOS 苹果内购详细步骤

    一 设置协议等相关 1 点击协议 税务和银行业务 2 点击 Request Contracts 下面的 Request 一直点击直到主协议界面 主协议界面 Contact info 联系人信息 Bank info 银行信息 Tax info