。
【摘要】在uniapp的开发中,避免不了的要对接支付,这里介绍一下对接的IOS应用内支付的相关内容
【背景】聚焦软件高定制开发解决方案的一家上海高新技术企业,成立10年(2014年成立),APP定制开发、小程序定制开发、物联网等领域, 与时俱进开发了大量的通用模块和产品: AI、OpenAI,LLM、移动支付、微信支付、免密支付,都是我们的专长领域,我们有足够强大的UI、产品、团队,特别是有一个开放的开发社区。 我们的开发资源,包含代码、软著、算法、甚至是技术团队,均可贡献给客户。
一、App Store协议、税务和银行业务
1.1 登录Apple开发者账号
* 登录地址:https://developer.apple.com/account * 选择协议、税务和银行业务
1.2 选择申请合同类型
进入协议、税务和银行业务页面后,会有3种合同类型,如果你之前没有主动申请过去合同,那么一般你现在激活的合同只有iOS Free Application一种。
页面内容分为两块:
Request Contracts(申请合同)
Contracts In Effect(已生效合同)。
合同类型分为3种:
iOS Free Application(免费合同应用)
iOS Paid Application(付费合同应用)
iAd App NetNetwork(广告合同)
1.3 申请iOS Paid Application合同
当我们点击申请iOS Paid Application合同后,该合同的状态会变成如下的样子,我们可以看到其中Status为Pending Tax, Bank, Contact。意思是联系方式、银行和税务信息没有填写。
1.4 添加银行帐户
填写银行CNAPS Code(ABA汇款路线号码)
1.5 报税
默认美国打勾,其他有的话打勾,一般都没
选择美国U.S Tax Forms,选择后会问你两个问题
第一个问题如下:询问你是否是美国居民,有没有美国伙伴关系或者美国公司,如果没有直接选择No。
第二个问题如下:询问你有没有在美国的商业性活动,没有也直接选No。
1.5.1 填写税务信息
包括以下几点:
Individual or Organization Name:个人或者组织名称
Country of incorporation: 所在国家
Type of Beneficial Owner:受益方式,独立开发者选个人
Permanent Residence:居住地址
Mailing address:邮寄地址
Name of Person Making this Declaration:声明人
Title:头衔
填写完这些信息后就可以提交了
1.5.2 填写联系信息,如果是个人开发者就全写自己
1.6 等待审核
当你填写完所有资料后,合同状态就会变成Processing,大约半天就通过了。
二、苹果内购IAP(In-App Purchase)
什么是内购?
如果你购买的商品,是在本app中使用和消耗的,就一定要用内购,否则会被拒绝上线,例如:游戏币,在线书籍,app中使用的道具等虚拟产品。如果购买的就是普通的商品,例如淘宝买东西等,就不需要用内购。内购的话,苹果公司需要抽取30%左右佣金。
苹果内购价格表中的实际收入是动态变化的,会根据税收变化而发生改变,一般苹果会收取30%左右的金额。但是表格里边的价格和等级一般是不变的。
当然,打赏功能被纳入内购项目中。所以例如微信打赏功能、直播项目打赏主播都必须采用内购。
可以简单理解成,带有内购功能的项目以后的成本会比安卓、PC端高出30%成本 。
内购使用场景:爱奇艺APP购买会员,QQ斗地主里面的充值QB等。
支付弹窗图标、价格、详情等都需要到https://developer.apple.com里面去设置。具体下面会讲到。
2.1 适用范围
在App内需要付费使用的产品功能或虚拟商品/服务,如游戏道具、电子书、音乐、视频、订阅会员、App的高级功能等。
App内购买实体商品(如淘宝买衣服)不适用IAP,不在App内使用的虚拟商品(如充话费)或服务(如滴滴叫车)也不适用IAP。 那么问题来了,假如在App内购买一个音乐专辑,既能在App里面听数字专辑,同时也能获得实体商品cd,适不适用IAP呢? 答案是适用的。因为App内的数字专辑和实体商品cd在使用上是可以分离的,数字专辑符合IAP的适用范围,购买就要用IAP。否则各种游戏里面卖648的道具,都声称商品不仅包含游戏道具,购买后还能获得一个5毛钱的实体纪念品(举例),就直接绕过IAP,苹果岂不完蛋? 苹果规定,适用范围内的虚拟商品或服务,必须使用IAP购买支付,不允许使用支付宝、微信支付等其它支付方式(包括Apple Pay),也不允许以任何方式(包括跳出App、提示文案等)引导用户通过应用外部渠道购买。
原则上苹果也不允许通过外部兑换码等方式在应用内解锁虚拟商品或服务,但实际上兑换码的限制是有些模糊的,因为有些App可以在应用内获得兑换码(比如活动发放优惠券或签到奖励),很难严格界定是一个外部兑换码还是内容兑换码。因此,在IAP购买中使用优惠券抵扣一般情况下是允许的,但如果很明显地引导用户在App外购买兑换码,再在App内兑换成虚拟商品或服务,是会被苹果Reject的。
2.2 IAP类型
如前面说的,IAP是一套商品交易系统,而非简单的支付系统。每一个购买项目都需要在App的itunes connect后台创建一个商品,提交给苹果审核,审核通过后,购买项目才会生效。
在创建IAP商品时,主要有4种类型可供选择:
2.2.1 Consumable products (消耗型商品)
该类型适用于可多次购买的消耗型项目,如游戏道具、虚拟币等。
2.2.2 Non-consumable products(非消耗型商品)
该类型适用于一次购买永久有效的项目,如电子书、游戏关卡等。
该类型项目支持跨设备同步和本地restore,比如说,用户在某个App中购买了一本书,可在所有相同Apple ID设备的App中免费获取这本书,而不要需要借助App本身的帐号体系,即使在App中删除了这本书,也可免费重新获取。
2.2.3 Non-renewable subscriptions(非续期订阅)
该类型适用于固定有效期的非自动续费项目,如云音乐的会员和一些视频App的会员。没有跨设备同步和本地restore机制,用户可以多次购买。
2.2.4 Auto-renewable subscriptions(自动续期订阅)
该类型适用于自动续费的订阅项目,如Apple Music的按月订阅,用户购买后会每月自动续费,直到用户手动取消或者开发者下架IAP项目。
类似Non-consumable products,该类型也支持跨设备同步和本地restore机制。
之前这种类型只支持newsstand类别(报刊杂志)的App,从2016年6月开始支持所有类型的App,但除了newsstand类别之外,国内的App很少使用这种类型的内购。
其中需要特别注意的是:
1 针对Non-consumable products类型的IAP项目,苹果会要求App提供一个“恢复购买”的功能,以支持跨设备同步和本地restore。同时,如果App本身有用户帐号系统,那么用户只要付费一次,就可以通过restore机制将IAP项目无限复制到多个用户帐号下。 因此,对于类似电子书之类的一次购买永久有效的项目,如果希望使用App本身的用户帐号系统,避开跨设备同步和本地restore机制,可以考虑选择Non-renewable subscriptions类型。同时,考虑到Non-renewable subscriptions一般是有固定有效期的,可以加一个无限长的有效期(比如9999天),以应对苹果审核。
2 Consumable products和Non-renewable subscriptions都是可以重复购买的IAP项目,前者更偏向消耗品,后者更偏向订阅品。另外还有一个区别是,针对Non-renewable subscriptions的IAP项目,用户如果之前已经买过一次,过期后再次购买或者切换App帐号后购买,支付流程中会出现一个系统弹窗提示用户之前已经购买过该项目,是否要再次购买,如果用户不小心点了取消,支付流程就会终止。 苹果设计这个弹窗的本意更多是根据Apple ID识别用户身份,避免用户重复购买相同项目。但对于有用户帐号体系的App,这个提示是有点多余的,虽然影响不大。因此,如果一个IAP项目既适用于Consumable products也适用于Non-renewable subscriptions,比较建议选择Consumable products。
2.3 创建IAP项目,以消耗性商品为例
App内购项目的审核必须跟着APP的第一个版本提交审核,在第一个内购项目审核通过之后,后续再添加的内购项目可以单独进行提交审核
2.3.1 添加内购项目
产品ID必须是唯一的,并且一旦设置,这个ID就不能再次使用,即使在这个内购项目删除之后,已经设置的产品Id也不能再次使用
在添加完内购项目之后,状态为“元数据丢失”,接下来就是供应情况及价格的设置
2.3.2 设置供应情况
这里主要设置提供 App 内购买的国家或地区,这里可以全选,也可以直选择某些国家或地区
2.3.3 设置价格信息
这里主要设置初始价格。此价格将决定 App Store 定价和你的收入。如果 App 内购买项目为付费,你必须拥有付费应用程序协议。
协议的内容和设置在第一部分已经进行了说明
在选价格的时候可以选择你所在的国家和地区,并选择对应的货币价格
在选择完地区和价格之后,点击下一步,会对基于所在国家或地区换算的所有国家或地区的相应价格,当然你也可以针对单个国家或地区选取不同价格。
点击下一步确认国家或地区的价格信息
2.3.4 添加本地化版本
这里主要设置你的 App 内购买项目的显示名称和描述,将在 App Store 上显示这些信息。
2.3.5 填写内购项目的审核信息
这里需要上传调用应用内支付的产品列表及定价页面,这个是必填的,这里 需要注意的是:上传图片的尺寸为1242px * 2208px或者1242px * 2688px
审核备注为非必填项
2.4 提交审核
在以上进行填写完成后,点击存储,此时的状态会变更为“准备提交”
此时在APP版本信息页面,将刚刚添加的内购项目添加进行,然后点击提交审核,等待审核结构即可
这里还需要注意的是,在内购项目添加完成后就可以进行开发了,也就是这时候在沙箱环境下是可以正常进行IOS内购项目的支付调用测试的
三、在uniapp中对接IOS的应用内支付
在使用uniapp对接IOS的应用内支付时有两种方式可以使用
使用uniapp的第三方服务中的API
使用插件市场中的unipay插件
3.1 使用第三方服务中API
官方文档
3.1.1支付流程
获取支付通道 (uni.getProvider)
```javascript uni.getProvider({ service: 'payment', success: (res) => { const iapChannel = res.providers.find((channel) => { return (channel.id === 'appleiap') })
// 如果 iapChannel 为 null,说明当前包没有包含iap支付模块。注意:HBuilder基座不包含 iap 通道
}
}); ```
通过支付通道获取产品列表 (iapChannel.requestProduct)
iapChannel.requestProduct( success, fail) success` 回调值类型 `Array
检查是否存在未关闭的订单 (iapChannel.restoreCompletedTransactions, 可选在合适的时机检查)
iapChannel.restoreCompletedTransactions( success, fail) success` 回调值类型 `Array
请求支付,传递产品信息 (uni.requestPayment)
js uni.requestPayment({ provider: 'appleiap', orderInfo: {}, success: (e) => { // e 类型为 Transaction, 详见下面的描述 } })
参数说明
属性
类型
默认值
说明
productid
String
产品id,在苹果开发者中心配置
username
String
透传参数,一般用于标记订单和用户的关系,向苹果服务器二次验证票据时返回此字段
quantity
Number
1
购买数量,至少大于等于 1
manualFinishTransaction
Boolean
false
3.5.1+ 支持,手动关闭订单,值为 false 时支付完成后自动关闭订单,true时不关闭订单,需要在合适的时机调用 finishTransaction 关闭订单。建议设置为 true, 默认值为 false 是为了向下兼容
paymentDiscount
Object
否
促销优惠(HBuilderX 3.7.0+ 手机系统iOS12.2+支持)
属性
类型
必填
说明
offerIdentifier
String
是
促销id
keyIdentifier
String
是
密钥
nonce
String
是
唯一id (必须小写 24小时有效)
signature
String
是
签名
timestamp
Number
是
创建证书的时间戳(毫秒 24小时有效)
属性
类型
说明
title
String
产品标题
description
String
产品描述
productid
String
产品id,在苹果开发者中心配置
price
Number
价格
pricelocal
String
币种,例如: zh_CN@currency=CNY
discount
Array
折扣信息(HBuilderX 3.7.0+ 手机系统iOS12.2+支持)
属性
类型
说明
payment
Object
支付信息,详见下面的说明
transactionDate
String
交易日期,示例 2022-01-01 08:00:00
transactionIdentifier
String
交易唯一标识
transactionReceipt
String
支付票据,用于在开发者的服务器向苹果的服务器二次验证交易是否有效
transactionState
String
交易状态码
属性
类型
说明
productid
String
产品id
quantity
String
购买数量
username
String
透传参数
客户端接收苹果返回的支付票据发送到服务器,在服务器请求苹果服务器验证支付是否有效
服务器验证票据有效后在客户端关闭订单 (iapChannel.finishTransaction)
iapChannel.finishTransaction(Transaction, success, fail) 所有 `fail` 回调格式为 `{ errCode: xxx, errMsg: '' }`
注意事项
相同订单,重复调用 restoreCompletedTransactions
后 transactionReceipt
会发生变化,并非唯一值
调用 finishTransaction
关闭订单可能不会立即生效,取决于苹果的服务器
沙盒环境:一个测试账号相同产品仅能购买一次,重复测试需要清除购买记录或重新添加沙盒测试账号
沙盒环境:调用 restoreCompletedTransactions
长时间无反应,检查设备登陆的沙箱账号是否正常
3.1.2 沙箱账号
登陆苹果开发者中心,添加沙箱账号
手机或iPad登陆沙箱账号,在 系统设置 -> App Store
3.1.3 订单丢失场景
用户没有绑定 AppStore
支付方式,调用 uni.requestPayment()
准备支付,触发失败 fail
回调,errCode=2,用户未绑定支付方式,app内支付流程结束。 系统弹出框引导用户绑定支付方式,此过程将跳转到系统应用 AppStore
进行绑定支付方式,绑定成功同步支付成功,用户成功付款
3.1.4 示例代码
3.2 使用unipay进行对接
插件地址
文档地址
3.2.1注意:只能使用uni-pay支付组件发起
// 发起ios内购支付
this.$refs.pay.createOrder({
provider: "appleiap", // 支付供应商(这里固定未appleiap,代表ios内购支付)
order_no: "20221027011000101001010", // 业务系统订单号
out_trade_no: "2022102701100010100101001", // 插件支付单号
type: "appleiap", // 支付回调类型(可自定义,建议填写appleiap)
productid: "io_dcloud_hellouniapp_pay_like6", // ios内购产品id(仅ios内购生效)
// 自定义数据
custom: {}
});
3.2.2 ios内购注意事项
ios内购支付需勾选App模块配置中的Apple应用内支付
需要打ios自定义基座
需要注册ios开发者账号,且交了年费(688元/年)
需要在ios开发者平台添加内购商品,并获得商品id
ios沙箱测试时,需要先在ios开发者平台添加沙箱测试账号,同时你的测试手机上需要登录ios沙箱账号
目前hbx版本热刷新会导致ios支付无法正常调用,因此每次修改完代码保存后,需要先关闭手机App,然后hbx重启项目,再打开手机app。(后面HBX会修复此问题)
3.2.3 完整ios内购支付示例代码
{{item.title}} {{item.price}}元
立即支付
四、开发过程中遇到的问题
测试时候的bundle Id必须要和申请内购项目的bundle id保持一致
再提交审核的时候,第一个内购项目必须和APP的版本一起提交审核,否则可能会被拒绝
在提交审核时要特别注意一下,如果有使用微信登录的话,那必须同时使用Apple登录,否则不会给通过的
在使用unipay对接的时候,需要使用云服务,可以使用DCloud,也可以使用自己的云服务,具体使用内容在官方文档中都有详细的描述
使用沙箱环境进行测试的时候,沙箱测试账号只能购买一次,如果需要多次购买,可以登录Apple开发平台,进入沙箱环境,把测试账号的购买记录清空
欢迎关注 智创有术我们凭团队实例运作以下专栏, 必须干货!