vonfly
vonfly
  • 发布:2024-04-17 11:53
  • 更新:2024-11-05 16:58
  • 阅读:414

【报Bug】ios端取消订阅产品后,再次购买订阅产品不会重新拉起支付,而是直接进入支付成功回调

分类:uni-app

产品分类: uniapp/App

PC开发环境操作系统: Windows

PC开发环境操作系统版本号: windows10 v2009

HBuilderX类型: 正式

HBuilderX版本号: 3.99

手机系统: iOS

手机系统版本号: iOS 15

手机厂商: 苹果

手机机型: iPhone6s Plus

页面类型: vue

vue版本: vue2

打包方式: 云端

项目创建方式: HBuilderX

示例代码:
import {  
    Iap,  
    IapTransactionState,  
} from "@/utils/iap.js"  
export default {  
    data() {  
        return {  
            // 获取苹果真实的产品列表  
            iapProductList: [],  
            loading: false,  
            disabled: true,  
            personId: uni.getStorageSync("personId"),  
            quantity: 1,  
        }  
    },  
    methods: {  
        // 初始化支付环境  
        initPayEnv(products) {  
            this._iap = new Iap({  
                products  
            })  
            this.init();  
        },  
        async init() {  
            uni.showLoading({  
                title: '正在检测支付环境...'  
            });  

            try {  
                await this._iap.init();  
                this.iapProductList = await this._iap.getProduct();  
                this.disabled = false;  
            } catch (e) {  
                uni.showToast({  
                    icon: 'none',  
                    title: '支付环境检测失败',  
                    duration: 2000  
                });  
            } finally {  
                uni.hideLoading();  
            }  
            if (this._iap.ready) {  
                this.restore();  
            }  
        },  
        async restore() {  
            this.loading = true;  
            this.disabled = true  
            // 检查上次用户已支付且未关闭的订单,可能出现原因:首次绑卡,网络中断等异常  
            // 提示是正在检测支付环境,实际是正在检测未关闭的订单  
            uni.showLoading({  
                title: '正在检测支付环境...'  
            });  

            try {  

                // 从苹果服务器检查未关闭的订单,可选根据 username 过滤,和调用支付时透传的值一致  
                const transactions = await this._iap.restoreCompletedTransactions({  
                    username: ''  
                });  

                console.log(transactions)  

                if (!transactions.length) {  
                    return;  
                }  

                for (var i = 0; i < transactions.length; i++) {  
                    let transaction = transactions[i]  
                    switch (transaction.transactionState) {  

                        case IapTransactionState.purchased:  
                            // 用户已付款,在此处请求开发者服务器,在服务器端请求苹果服务器验证票据  
                            const username = transaction.payment.username || uni.getStorageSync(  
                                'IAP_ORDER_USERNAME');  
                            console.log('username', username)  
                            if (!username) {  
                                return await this._iap.finishTransaction(transaction);  
                            }  
                            this.validatePaymentResult(username, transaction);  
                            break;  
                        case IapTransactionState.failed:  
                            // 关闭未支付的订单  
                            await this._iap.finishTransaction(transaction);  
                            break;  
                            // case IapTransactionState.restored:  
                            //  // 关闭未支付的订单  
                            //  this.validatePaymentResult(username, transaction);  
                            //  break;  
                        default:  
                            break;  
                    }  
                }  
            } catch (e) {  
                uni.showToast({  
                    icon: 'none',  
                    title: e.message,  
                    duration: 2000  
                });  
            } finally {  
                this.loading = false  
                this.disabled = false  
                uni.hideLoading();  
            }  
        },  
        async onPayment() {  
            if (this.loading === true) {  
                return;  
            }  
            this.loading = true;  
            this.disabled = true  

            try {  

                // 从开发者服务器创建订单  
                const orderInfo = await this.$u.post('/api/finance/CreateIAPOrder', {  
                    "PersonId": this.personId,  
                    "CoinCount": this.currProductInfo.Price,  
                    "ProductId": this.currProductId  
                })  

                console.log(orderInfo)  

                if (orderInfo && orderInfo.Status) {  
                    // 本地缓存username  
                    uni.setStorageSync('IAP_ORDER_USERNAME', orderInfo.UserName);  
                } else {  
                    uni.showToast({  
                        icon: 'none',  
                        title: '订单创建失败,请联系管理员',  
                        duration: 3000  
                    });  
                    uni.hideLoading()  
                    return  
                }  

                // 请求苹果支付  
                const transaction = await this._iap.requestPayment({  
                    productid: this.currProductId,  
                    username: orderInfo.UserName,  
                    quantity: this.quantity,  
                    manualFinishTransaction: true,  
                });  

                console.log('transaction', transaction)  

                if (transaction.transactionState === IapTransactionState.purchased) {  
                    // 在此处请求开发者服务器,在服务器端请求苹果服务器验证票据  
                    const res = await this.validatePaymentResult(transaction.payment.username, transaction)  
                    if (res.ReturnCode === 1001) {  
                        // 支付成功,重新获取用户余额  
                        uni.showToast({  
                            icon: 'success',  
                            title: '支付成功',  
                            duration: 2000  
                        });  
                        // 触发统一的支付成功函数,由各个业务页面自行处理成功逻辑  
                        this.paySuccess()  
                    } else {  
                        uni.showToast({  
                            icon: 'none',  
                            title: res.MessageChinese,  
                            duration: 3000  
                        });  
                    }  
                    uni.hideLoading()  
                    this.onPaySuccessReset()  
                }  
            } catch (e) {  
                console.log(e)  
                uni.setStorageSync('IAP_ORDER_USERNAME', '');  
                if (e.errCode === 2 && e.code === 2) {  
                    uni.showToast({  
                        icon: 'none',  
                        title: '支付已取消',  
                        duration: 2000  
                    });  

                } else {  
                    uni.showToast({  
                        icon: 'none',  
                        title: e.message,  
                        duration: 2000  
                    });  
                }  
                uni.hideLoading()  
                this.onPaySuccessReset()  
            } finally {  
                // this.onPaySuccessReset()  
            }  
        },  
        // 向本地服务器验证支付结果  
        async validatePaymentResult(userName, transaction) {  
            const serverRes = await this.$u.post('/api/finance/IAPOrderVerify', {  
                "UserName": userName,  
                "TransactionReceipt": transaction.transactionReceipt,  
            })  
            console.log(serverRes)  
            if (serverRes.ReturnCode === 1001) {  
                uni.setStorageSync('IAP_ORDER_USERNAME', '');  
                // 验证成功后关闭订单  
                await this._iap.finishTransaction(transaction);  
            }  
            return serverRes  
        }  
    }  
}  

操作步骤:

ios测试环境:沙盒环境

场景一:在每次支付前不调用restoreCompletedTransactions api的情况下,订阅产品在订阅状态下,再次购买苹果系统会提示“你目前已订阅此项目”

场景二:在每次支付前调用restoreCompletedTransactions api的情况下,订阅产品在订阅状态下,再次购买会直接进入支付成功回调,无提示。

场景三:在产品订阅情况下,进入设置->App Store->沙盒账户->取消产品订阅,再进入app,在未调用restoreCompletedTransactions api后购买该订阅产品,会先执行支付成功回调,再弹出系统支付弹窗。

场景四:在产品订阅情况下,进入设置->App Store->沙盒账户->取消产品订阅,再进入app,在调用restoreCompletedTransactions api后购买该订阅产品,会直接进入支付成功回调,支付弹窗未弹出。同时,检查设置->App Store->沙盒账户->产品订阅状态还是未订阅状态

预期结果:

产品在未订阅状态下,可以订阅成功。产品在已订阅状态下,有系统提示用户。

实际结果:

无法形成订阅产品支付闭环

bug描述:

ios测试环境:沙盒环境

场景一:在每次支付前不调用restoreCompletedTransactions api的情况下,订阅产品在订阅状态下,再次购买苹果系统会提示“你目前已订阅此项目”

场景二:在每次支付前调用restoreCompletedTransactions api的情况下,订阅产品在订阅状态下,再次购买会直接进入支付成功回调。

场景三:在产品订阅情况下,进入设置->App Store->沙盒账户->取消产品订阅,再进入app,在未调用restoreCompletedTransactions api后购买该订阅产品,会先执行支付成功回调,再弹出系统支付弹窗。

场景四:在产品订阅情况下,进入设置->App Store->沙盒账户->取消产品订阅,再进入app,在调用restoreCompletedTransactions api后购买该订阅产品,会直接进入支付成功回调,支付弹窗未弹出。同时,检查设置->App Store->沙盒账户->产品订阅状态还是未订阅状态

2024-04-17 11:53 负责人:无 分享
已邀请:
vonfly

vonfly (作者) - 中端开发工程师

顶下

vonfly

vonfly (作者) - 中端开发工程师

有官方同学解答下吗?

1***@qq.com

1***@qq.com

+1 我也遇到了

y***@163.com

y***@163.com

顶,好多问题啊

pengcheng933

pengcheng933

建议用原生插件来解决这个问题

  • y***@163.com

    不会原生的

    2024-07-24 14:09

  • pengcheng933

    回复 y***@163.com: 我写了个,https://ext.dcloud.net.cn/plugin?id=17130

    2024-07-24 17:24

y***@163.com

y***@163.com

生产环境也这样,会返回初次的订单记录,而不是拉起支付弹窗,官方能不能看看问题啊,服了

  • y***@163.com

    根据DCloud_iOS_WZT大佬的指导已经解决了问题,我没有使用官方的iap.js,所以在调用iapChannel.finishTransaction(Transaction, <Function> success, <Function> fail)原生函数的时候我没有传递success、fail这两个回调函数导致关闭交易失败了。

    2024-09-03 16:46

  • PenGuin1

    回复 y***@163.com: 我使用官方的iap.js,但是也碰到了同样的问题

    2024-11-05 16:58

PenGuin1

PenGuin1

有没官方的人出来解释下哇

  • y***@163.com

    解决了,刚开始是因为没有关闭交易,后面沙盒环境这样是因为有延迟问题,取消订阅后需要等待20分钟后再次发起支付就可以拉起弹窗了

    2024-11-05 17:00

  • PenGuin1

    回复 y***@163.com: 每次支付前都会restore,然后关闭订单吗

    2024-11-05 17:14

  • PenGuin1

    回复 y***@163.com: restore后无法重新订阅(拉起订阅弹窗)

    2024-11-05 17:16

  • vonfly (作者)

    回复 PenGuin1: 你取消订阅之后过一段时间再试试呢

    2024-11-11 09:48

要回复问题请先登录注册