virtual-payment.uvue 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. <template>
  2. <!-- #ifdef APP -->
  3. <scroll-view style="flex: 1;">
  4. <!-- #endif -->
  5. <page-head title="虚拟支付"></page-head>
  6. <view style="padding-left: 20px; padding-right: 20px;">
  7. <text>
  8. requestVirtualPayment api 适用于消耗性类型、非消耗性类型、自动续期订阅类型、非自动续期订阅类型产品的购买。\n\n
  9. 1. 消耗性类型:该类型的产品可以设置购买数量,默认是1,最大值是10; \n
  10. 2. 非消耗性类型、自动续期订阅类型、非自动续期订阅类型: 这些类型的产品购买数量设置无效,数量只能是1; \n
  11. 3. 非消耗性类型:该类型产品一个appleId只能购买一次,可以在任何登陆该appleId账号的设备上restore获取。
  12. </text>
  13. <button style="margin-top: 20px;" type="primary" v-for="(item,index) in productList" :key="index"
  14. @click="requestVirtualPayment(item)">{{item.name}}</button>
  15. <text>
  16. \nrestoreTransactions api 适用于非消耗性类型、自动续期订阅类型、非自动续期订阅类型产品的购买。\n\n
  17. 1. 非消耗性类型: 返回每个已购买的非消耗性类型产品的购买记录;\n
  18. 2. 自动续期订阅类型: 返回每个已购买的自动续期订阅类型产品的最新购买记录,沙盒账号最多可自动续订 12 次;\n
  19. 3. 非自动续期订阅类型: 返回每个已购买的非自动续期订阅类型产品的最新购买记录, 该类型订阅可以连续多次购买,开发者需要自己的后台计算产品过期的时间。\n
  20. Note: 不能用来恢复消耗性类型的购买记录。
  21. </text>
  22. <button style="margin-top: 20px;" type="primary" @click="restoreTransactions">恢复购买订单列表</button>
  23. <text>
  24. \ngetUnfinishedTransactions api 适用于获取未完成的各种类型产品的购买记录(用来防止丢单)。\n\n
  25. 1. 比如用户点击购买已经付款成功,但因网络、手机没电关机等特殊情况,Apple IAP
  26. 没有返回客户端对应的购买凭证,从而导致无法finish该交易导致的丢单,可以在需要的地方调用该api获得此类未finished的交易记录; \n
  27. 2. 针对消耗性类型产品交易,只能通过该api获取未finished的交易,防止丢单;\n
  28. 3. 对于其他类型产品未finished交易, 不仅可以通过该api获取,也可以通过restoreTransactions api (也可获取已经finished的交易)获取;
  29. </text>
  30. <button style="margin-top: 20px; margin-bottom: 50px;" type="primary"
  31. @click="getUnfinishedTransactions">获取未结束的订单列表</button>
  32. </view>
  33. <!-- #ifdef APP -->
  34. </scroll-view>
  35. <!-- #endif -->
  36. </template>
  37. <script>
  38. export type PayItem = { id : string, name : string, quantity ?: number }
  39. export default {
  40. data() {
  41. return {
  42. productList: [] as PayItem[],
  43. virtualPaymentManager: Object
  44. }
  45. },
  46. onLoad: function () {
  47. this.virtualPaymentManager = uni.getVirtualPaymentManager()
  48. this.initProductList()
  49. },
  50. methods: {
  51. initProductList() {
  52. this.productList.push({
  53. name: '消耗性产品:个人赞助1元',
  54. id: this.isDebug() ? "uniappx.consumable.sponsor_1" : "uniappx.consumable.sponsor1",
  55. quantity: 1
  56. } as PayItem);
  57. this.productList.push({
  58. name: '消耗性产品:金牌赞助5元, 数量=2',
  59. id: this.isDebug() ? "uniappx.consumable.sponsor_50" : "uniappx.consumable.sponsor50",
  60. quantity: 2
  61. } as PayItem);
  62. this.productList.push({
  63. name: '非消耗性产品: 赞助特效1元',
  64. id: this.isDebug() ? "uniappx.nonconsumable.sponsorskin_1" : "uniappx.nonconsumable.sponsorskin1"
  65. } as PayItem);
  66. // this.productList.push({
  67. // name: '自动续期订阅产品:每月定期赞助1元',
  68. // id: this.isDebug() ? "uniappx.autorenewable.monthly_1" : "uniappx.autorenewable.monthly1"
  69. // } as PayItem);
  70. this.productList.push({
  71. name: '非自动续期订阅产品:月赞助1元',
  72. id: this.isDebug() ? "uniappx.nonrenewable.monthly_1" : "uniappx.nonrenewable.monthly1"
  73. } as PayItem);
  74. // this.productList.push({
  75. // name: '测试不存在的产品',
  76. // id: "uniappx.nonrenewable.none"
  77. // } as PayItem);
  78. },
  79. getPackageName() : string {
  80. const res = uni.getAppBaseInfo();
  81. let packageName : string = ""
  82. // #ifdef APP-ANDROID
  83. packageName = res.packageName
  84. // #endif
  85. // #ifdef APP-IOS
  86. packageName = res.bundleId
  87. // #endif
  88. return packageName
  89. },
  90. isDebug() : boolean {
  91. if (this.getPackageName() == 'io.dcloud.uniappx') {
  92. return true
  93. }
  94. return false
  95. },
  96. isProd() : boolean {
  97. if (this.getPackageName() == 'io.dcloud.hellouniappx') {
  98. return true
  99. }
  100. return false
  101. },
  102. isCustom() : boolean {
  103. if (this.isDebug() == false && this.isProd() == false) {
  104. return true
  105. }
  106. return false
  107. },
  108. requestVirtualPayment(e : PayItem) {
  109. uni.showLoading({
  110. title: "",
  111. mask: true
  112. });
  113. uni.requestVirtualPayment({
  114. //需要将orderId转换为如下符合UUID规则的字符串,然后赋值给参数appAccountToken, 传入不符合UUID规则的字符串无效
  115. apple: {
  116. productId: e.id,
  117. appAccountToken: "123eaaaa-e89b-12d3-a456-42661417400b",
  118. quantity: e.quantity ?? 1,
  119. },
  120. success: (res) => {
  121. uni.hideLoading()
  122. console.log("购买成功:该productId= " + res.apple?.productId)
  123. //TODO: 开发者server验证逻辑
  124. //经过开发者server验证成功后请结束该交易
  125. uni.showToast({
  126. title: "购买成功:" + res.apple?.productId,
  127. icon: 'success'
  128. })
  129. this.virtualPaymentManager.finishTransaction({
  130. transaction: res.apple,
  131. success: (r) => {
  132. console.log("关单成功, 该productId= " + res.apple?.productId)
  133. },
  134. fail: (e) => {
  135. console.log("关单失败, 该productId= " + res.apple?.productId)
  136. }
  137. })
  138. },
  139. fail: (e) => {
  140. uni.hideLoading()
  141. console.log("购买失败:errSubject= " + e.errSubject + ", errCode= " + e.errCode + ", errMsg= " + e.errMsg)
  142. uni.showToast({
  143. title: "购买失败错误码:" + e.errCode,
  144. icon: 'error'
  145. })
  146. }
  147. })
  148. },
  149. restoreTransactions() {
  150. uni.showLoading({
  151. title: "",
  152. mask: true
  153. });
  154. this.virtualPaymentManager.restoreTransactions({
  155. success: (res) => {
  156. uni.hideLoading()
  157. console.log("restore成功的交易个数:" + res.transactions.length)
  158. res.transactions.forEach(transaction => {
  159. //TODO: 开发者server验证逻辑
  160. console.log("restore成功的交易productId= " + transaction.productId)
  161. })
  162. uni.showToast({
  163. title: "restore成功的交易个数:" + res.transactions.length,
  164. icon: 'success'
  165. })
  166. },
  167. fail: (e) => {
  168. uni.hideLoading()
  169. console.log("restore失败:errSubject= " + e.errSubject + ", errCode= " + e.errCode + ", errMsg= " + e.errMsg)
  170. uni.showToast({
  171. title: "restore失败错误码:" + e.errCode,
  172. icon: 'error'
  173. })
  174. }
  175. })
  176. },
  177. getUnfinishedTransactions() {
  178. uni.showLoading({
  179. title: "",
  180. mask: true
  181. });
  182. this.virtualPaymentManager.getUnfinishedTransactions({
  183. success: (res) => {
  184. uni.hideLoading()
  185. console.log("获取未结束的订单列表个数:" + res.transactions.length)
  186. uni.showToast({
  187. title: "获取未结束的订单列表个数:" + res.transactions.length,
  188. icon: 'success'
  189. })
  190. res.transactions.forEach(transaction => {
  191. console.log("getUnfinishedTransactions成功的交易productId= " + transaction.productId)
  192. //TODO: 开发者server验证逻辑
  193. //经过开发者server验证成功后请结束该交易
  194. this.virtualPaymentManager.finishTransaction({
  195. transaction: transaction,
  196. success: (r) => {
  197. console.log("关单成功, 该productId= " + transaction.productId)
  198. },
  199. fail: (e) => {
  200. console.log("关单失败, 该productId= " + transaction.productId)
  201. }
  202. })
  203. })
  204. },
  205. fail: (e) => {
  206. uni.hideLoading()
  207. console.log("获取未结束的订单列表失败:errSubject= " + e.errSubject + ", errCode= " + e.errCode + ", errMsg= " + e.errMsg)
  208. uni.showToast({
  209. title: "获取未结束的订单列表失败错误码" + e.errCode,
  210. icon: 'error'
  211. })
  212. }
  213. })
  214. }
  215. }
  216. }
  217. </script>
  218. <style>
  219. </style>