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

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

产品分类

uniapp/App

PC开发环境

  • 操作系统:Windows
  • 操作系统版本号:windows10 v2009

手机系统

  • 系统:iOS
  • 系统版本号:iOS 15
  • 手机厂商:苹果
  • 手机机型:iPhone6s Plus

开发工具

  • HBuilderX类型:正式
  • HBuilderX版本号:3.99

项目信息

  • 页面类型: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->沙盒账户->产品订阅状态还是未订阅状态

预期结果

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

实际结果

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

更多关于uni-app ios端取消订阅产品后,再次购买订阅产品不会重新拉起支付,而是直接进入支付成功回调的实战教程也可以访问 https://www.itying.com/category-93-b0.html

16 回复

顶下

更多关于uni-app ios端取消订阅产品后,再次购买订阅产品不会重新拉起支付,而是直接进入支付成功回调的实战教程也可以访问 https://www.itying.com/category-93-b0.html


有官方同学解答下吗?

+1 我也遇到了

顶,好多问题啊

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

不会原生的

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

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

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

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

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

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

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

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

uni-app 中,iOS 端的订阅产品在取消订阅后再次购买时,可能会出现直接进入支付成功回调的情况,而不是重新拉起支付。这通常是由于 Apple 的订阅机制导致的。以下是一些可能的原因和解决方案:

1. Apple 的订阅机制

  • 自动续订:Apple 的订阅产品在用户取消订阅后,如果用户再次购买相同的订阅产品,系统会自动续订,而不会重新拉起支付流程。这是因为 Apple 会认为用户已经同意继续订阅。
  • 支付成功回调:由于系统自动续订,支付流程不会再次触发,因此会直接进入支付成功回调。

2. 解决方案

  • 检查订阅状态:在用户尝试再次购买订阅产品之前,可以通过 uni-app 提供的 API 或 Apple 的服务器验证用户的订阅状态。如果用户已经订阅,可以提示用户不需要再次购买。
  • 引导用户重新订阅:如果用户确实需要重新订阅,可以引导用户到 Apple 的订阅管理页面,手动重新订阅。
  • 处理自动续订:在支付成功回调中,处理自动续订的逻辑,确保用户的订阅状态更新正确。

3. 代码示例

  • 检查订阅状态

    uni.request({
        url: 'https://api.apple.com/check_subscription_status', // 替换为实际的 Apple 服务器接口
        method: 'GET',
        success(res) {
            if (res.data.subscribed) {
                console.log('用户已经订阅,无需再次购买');
            } else {
                console.log('用户未订阅,可以继续购买');
            }
        },
        fail(err) {
            console.error('检查订阅状态失败', err);
        }
    });
    
  • 处理自动续订

    uni.requestPayment({
        provider: 'appleiap',
        orderInfo: {
            productId: 'your_subscription_product_id'
        },
        success(res) {
            console.log('支付成功', res);
            // 处理自动续订逻辑
            updateSubscriptionStatus(res);
        },
        fail(err) {
            console.error('支付失败', err);
        }
    });
    
    function updateSubscriptionStatus(res) {
        // 更新用户的订阅状态
        uni.request({
            url: 'https://your_server/update_subscription_status',
            method: 'POST',
            data: {
                transactionId: res.transactionId,
                subscriptionStatus: 'active'
            },
            success(response) {
                console.log('订阅状态更新成功', response);
            },
            fail(error) {
                console.error('订阅状态更新失败', error);
            }
        });
    }
回到顶部