应用内购买演示

一个演示应用内产品购买的完整移动应用程序。

注: Qt Purchasing 模块是Qt 6.0 中移除的模块之一,其代码现包含在本示例中,作为如何使用 Qt 与常见市场集成的指南。

该演示是什么?

该演示是一个基于经典猜词游戏 Hangman 的移动游戏应用程序,其中元音可以通过演示的内部商店购买。在游戏中,您将看到一排破折号,代表要猜测的单词的字母。只要猜对单词中出现的字母,该字母就会被放在单词中相应的一个或多个破折号上。猜中单词的每一个字母或随时猜对整个单词,游戏就结束了,您就赢了。如果猜错了,就会画出悬挂棒图的一个元素。一旦图形完成,你就猜对了,你就输了。

该演示展示了如何在 Qt 应用程序中为 Android 和 iOS 平台提供应用内产品。为了测试演示中的应用内购买功能,您必须首先在外部商店注册应用程序及其产品。有关如何注册的介绍,请分别参阅Google PlayApp Store指南。

第三方应用程序商店

应用程序内的产品必须先在目标商店注册,然后才能在应用程序中查询或购买。我们建议对每个商店中的产品使用相同的标识符,因为这样可以简化查询和购买产品的代码。

演示如何运行

该演示是一个 QML 应用程序,它注册 QML 类型以访问有关应用程序内产品的信息,并请求购买这些产品。这些产品在目标平台的外部商店中注册。

在应用程序中添加应用内购买时,首先要添加一个商店对象。在演示中,商店对象是由应用程序启动时加载的 MainView 组件创建的。

Store {
    id: iapStore
}

该演示定义了一个组件,用于显示购买应用内产品的商店。这些产品必须首先在 MainView 中创建的商店对象中注册。有两种产品可用,第一种是消耗品类型。

Product {
    id: product100Vowels
    store: iapStore
    type: Product.Consumable
    identifier: "qt.io.demo.hangman.100vowels"

    onPurchaseSucceeded: {
        console.log(identifier + " purchase successful");
        //Add 100 Vowels
        applicationData.vowelsAvailable += 100;
        transaction.finalize();
        pageStack.pop();
    }

    onPurchaseFailed: {
        console.log(identifier + " purchase failed");
        console.log("reason: "
                    + transaction.failureReason === Transaction.CanceledByUser ? "Canceled" : transaction.errorString);
        transaction.finalize();
    }
}

这种消耗品可提供 100 个额外的元音,供游戏中猜词时使用。购买成功后,我们将更新应用程序的状态,使其包含 100 个额外的元音。然后,我们在交易对象上调用 finalize() 来向平台商店确认已提供了该消耗品。

第二个产品是非消耗品类型,将来会永久解锁元音。除了在购买时更新应用程序状态外,我们还必须确保提供一种方法,以便在最终用户使用的其他设备上还原这次购买。在这种情况下,我们要为 onPurchaseRestored 创建一个信号处理程序。

Product {
    id: productUnlockVowels
    type: Product.Unlockable
    store: iapStore
    identifier: "qt.io.demo.hangman.unlockvowels"

    onPurchaseSucceeded: {
        console.log(identifier + " purchase successful");
        applicationData.vowelsUnlocked = true;
        transaction.finalize();
        pageStack.pop();
    }

    onPurchaseFailed: {
        console.log(identifier + " purchase failed");
        console.log("reason: "
                    + transaction.failureReason === Transaction.CanceledByUser ? "Canceled" : transaction.errorString);
        transaction.finalize();
    }

    onPurchaseRestored: {
        console.log(identifier + " purchase restored");
        applicationData.vowelsUnlocked = true;
        console.log("timestamp: " + transaction.timestamp);
        transaction.finalize();
        pageStack.pop();
    }
}

除了注册产品外,该演示还提供了实际购买注册产品的接口。该演示定义了一个名为StoreItem 的自定义组件,用于显示和处理购买交互。

Product {
    id: productUnlockVowels
    type: Product.Unlockable
    store: iapStore
    identifier: "qt.io.demo.hangman.unlockvowels"

    onPurchaseSucceeded: {
        console.log(identifier + " purchase successful");
        applicationData.vowelsUnlocked = true;
        transaction.finalize();
        pageStack.pop();
    }

    onPurchaseFailed: {
        console.log(identifier + " purchase failed");
        console.log("reason: "
                    + transaction.failureReason === Transaction.CanceledByUser ? "Canceled" : transaction.errorString);
        transaction.finalize();
    }

    onPurchaseRestored: {
        console.log(identifier + " purchase restored");
        applicationData.vowelsUnlocked = true;
        console.log("timestamp: " + transaction.timestamp);
        transaction.finalize();
        pageStack.pop();
    }
}

StoreItem 组件将显示从平台商店中查询到的产品数据,并在用户点击产品时调用购买()方法。

Text {
    id: titleText
    text: product.title
    font.bold: true
    anchors.right: priceText.left
    anchors.rightMargin: topLevel.globalMargin
    anchors.top: parent.top
    anchors.topMargin: topLevel.globalMargin
    anchors.left: parent.left
    anchors.leftMargin: topLevel.globalMargin
}

Text {
    id: descriptionText
    text: product.description
    anchors.right: priceText.left
    anchors.rightMargin: topLevel.globalMargin
    anchors.left: parent.left
    anchors.leftMargin: topLevel.globalMargin
    anchors.top: titleText.bottom
    anchors.topMargin: topLevel.globalMargin / 2
    wrapMode: Text.WordWrap
}

Text {
    id: priceText
    text: product.price
    anchors.right: parent.right
    anchors.rightMargin: topLevel.globalMargin
    anchors.verticalCenter: parent.verticalCenter
}

MouseArea {
    anchors.fill: parent
    onClicked: {
        pendingRect.visible = true;
        spinBox.visible = true;
        statusText.text = "Purchasing...";
        storeItem.state = "PURCHASING";
        product.purchase();
    }
    onPressed: {
        storeItem.state = "PRESSED";
    }
    onReleased: {
        storeItem.state = "NORMAL";
    }
}

Android 和 iOS 使用基类。在基类的基础上,Android 和 iOS 又有衍生类:

应用内购买

应用内购买是应用程序货币化的一种方式。这些购买在应用程序内部进行,包括从解锁内容到虚拟物品等任何内容。该演示使用系统应用程序接口进行应用内购买,这意味着购买流程对用户来说更加熟悉,而且平台已存储的信息(如信用卡信息)可用于简化购买流程。

许可证和归属

关于在 Android 上部署演示程序,请参阅AndroidGNU C++ 运行时许可,了解更多信息。

示例项目 @ code.qt.io

© 2025 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.