如何设置应用内购买(非消耗品)?

2024-03-17

我正在使用一些在线教程在我的应用程序中实现应用程序内购买。但该教程适用于消费品应用内购买。但就我而言,用户只需要购买一次。

我修改了代码,在购买应用内购买后禁用“购买按钮”。现在一切正常。但问题是,如果我关闭并打开应用程序,“购买按钮”就会启用。

这是我的 xml 代码

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
    android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".InAppBillingActivity">

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/click_string"
        android:id="@+id/clickButton"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="113dp"
        android:onClick="buttonClicked"/>

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/buy_string"
        android:id="@+id/buyButton"
        android:layout_centerVertical="true"
        android:layout_centerHorizontal="true"
        android:onClick="buyClick" />
</RelativeLayout>

这是我的应用内结算活动

public class InAppBillingActivity extends AppCompatActivity {

    private static final String TAG =
            "InAppBilling";
    IabHelper mHelper;
    static final String ITEM_SKU = "com.example.buttonclick";

    private Button clickButton;
    private Button buyButton;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_in_app_billing);

        buyButton = (Button)findViewById(R.id.buyButton);
        clickButton = (Button)findViewById(R.id.clickButton);
        clickButton.setEnabled(false);
        String base64EncodedPublicKey =
                "<place your public key here>";

        mHelper = new IabHelper(this, base64EncodedPublicKey);

        mHelper.startSetup(new
                                   IabHelper.OnIabSetupFinishedListener() {
                                       public void onIabSetupFinished(IabResult result) {
                                           if (!result.isSuccess()) {
                                               Log.d(TAG, "In-app Billing setup failed: " +
                                                       result);
                                           } else {
                                               Log.d(TAG, "In-app Billing is set up OK");
                                           }
                                       }
                                   });
    }

    public void buttonClicked (View view)
    {
        Intent Quiz = new Intent(getApplicationContext(), QuestionYearwises.class);
        startActivity(Quiz);
    }

    public void buyClick(View view) {
        mHelper.launchPurchaseFlow(this, ITEM_SKU, 10001,
                mPurchaseFinishedListener, "mypurchasetoken");
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode,
                                    Intent data)
    {
        if (!mHelper.handleActivityResult(requestCode,
                resultCode, data)) {
            super.onActivityResult(requestCode, resultCode, data);
        }
    }

    IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener
            = new IabHelper.OnIabPurchaseFinishedListener() {
        public void onIabPurchaseFinished(IabResult result,
                                          Purchase purchase)
        {
            if (result.isFailure()) {
                // Handle error
                return;
            }
            else if (purchase.getSku().equals(ITEM_SKU)) {
                consumeItem();
                buyButton.setEnabled(false);
            }

        }
    };
    public void consumeItem() {
        mHelper.queryInventoryAsync(mReceivedInventoryListener);
    }

    IabHelper.QueryInventoryFinishedListener mReceivedInventoryListener
            = new IabHelper.QueryInventoryFinishedListener() {
        public void onQueryInventoryFinished(IabResult result,
                                             Inventory inventory) {

            if (result.isFailure()) {
                // Handle failure
            } else {
                mHelper.consumeAsync(inventory.getPurchase(ITEM_SKU),
                        mConsumeFinishedListener);
            }
        }
    };

    IabHelper.OnConsumeFinishedListener mConsumeFinishedListener =
            new IabHelper.OnConsumeFinishedListener() {
                public void onConsumeFinished(Purchase purchase,
                                              IabResult result) {

                    if (result.isSuccess()) {
                        clickButton.setEnabled(true);
                    } else {
                        // handle error
                    }
                }
            };

    @Override
    public void onDestroy() {
        super.onDestroy();
        if (mHelper != null) mHelper.dispose();
        mHelper = null;
    }


}

每次用户打开应用程序时,您要做的第一件事就是检查购买状态。如果用户已经拥有购买的商品,请在应用程序中发布与购买相关的功能,然后只需将按钮可见性设置为View.GONE或者一些对你有意义的事情,我个人只是隐藏它。

如果您的购买是一次性购买,则不得消费,似乎在您的mPurchaseFinishedListener您正在消费它,然后当您在用户打开应用程序时检查该商品的所有权时,这似乎是递归购买,因为您已经消费了该商品,它将允许您再次购买。

您可能需要考虑使用Google Play 结算库 https://developer.android.com/google/play/billing/billing_library_overview,如果您使用的是带有AIDL它将被弃用see https://developer.android.com/google/play/billing/api.html.

这是一个Codelab https://codelabs.developers.google.com/codelabs/play-billing-codelab/#0让您开始使用Google Play 结算库

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何设置应用内购买(非消耗品)? 的相关文章

  • 通过代码在创建时突出显示 ListView 项目

    我想在创建 listView 时突出显示 ListView 的第一行 0 我尝试了不同的方法 就像您在注释代码中看到的那样 但没有任何效果 这很奇怪 因为 OnItemClickListener 中的突出显示工作正常 它通过 xml 选择器
  • Android中将JSON数据存储到本地数据库

    好的 我创建了一个应用程序 它使用 JSON 从我的服务器检索数据 现在我想将检索到的数据存储在手机的本地存储 数据库中 我该怎么做 我是android编程新手 这是我从服务器收到的 JSON messages id 44 issender
  • 如何在 Android 应用程序中隐藏 Flutterwave API 密钥

    我正在构建一个 Android 应用程序 目前正在将 Flutterwave 集成到我的应用程序中以进行支付 建议我永远不要将 Flutterwave API 密钥放在我的应用程序上 那么我该如何隐藏这些键呢 我正在使用 Retrofit
  • Android 中使用黑白 alpha 蒙版的高效位图蒙版

    我想用黑白 alpha 蒙版来掩盖位图 我的蒙版图像是黑白的 黑色区域意味着透明 白色区域意味着不透明 我需要的是 当我使用此蒙版图像来蒙版任何其他图像时 如果蒙版图像的相应区域为黑色 则生成的图像区域应为透明 否则 生成的图像区域应该是不
  • relativelayout导致动画不起作用?

    我有一个活动 其布局仅包含一个 VideoView 这是 XML
  • VOIP通话录音

    我正在开发一个在 android 中录制 VOIP 通话的项目 我没有找到任何解决方案 有很多应用程序支持手机上的 VOIP 录音 我找不到任何教程和帮助 立方体通话记录器 https play google com store apps
  • Play 商店中的应用描述更新

    我想更新应用程序的描述以及 Play 商店上的屏幕截图 但应用程序保持相同 即相同的版本号 我不想发布新应用程序 因为应用程序中没有任何更改 这可能吗 谷歌也会要求更新应用程序吗 您可以更新描述 也可以更改屏幕截图 您的应用程序将保持不变
  • 如何使用 Google 的 GithubBrowserSample 方法在片段之间共享视图模型?

    我对 Android 架构组件的使用非常陌生 因此我决定使用 GithubBrowserSample 来构建我的应用程序来实现我的许多用例 但我有一个问题 我不知道使用这种方法在片段之间共享视图模型的正确方法是什么 我想共享视图模型 因为我
  • 如何清除Android剪贴板?

    我发现的方法都不起作用 这是我尝试过的 1 使用clearPrimaryClip 的方法ClipboardManager class ClipboardManager clipboard ClipboardManager getSystem
  • 如何绘制部分位图圆弧?类似于圆形进度轮,但具有显示得越来越多的位图。

    我正在寻找的是一种以顺时针圆形方式显示图像的视图 当进度为 25 时 应显示前 90 度 当进度为 100 时 应绘制完整的 360 度 它与使用 canvas drawArc 非常接近 但此方法仅适用于 Paint 对象 不适用于位图 其
  • Jetpack Compose:制作全屏(绝对定位)组件

    我怎样才能在全屏渲染树的深处制作一个可组合的 类似于Dialog可组合作品 例如 当用户单击图像时 它会显示该图像的全屏预览 而无需更改当前路线 我可以用 CSS 来做到这一点position absolute or position fi
  • Android 认为我没有关闭数据库!为什么?

    我有一个 SQLiteDatabase 数据成员 我在 onCreate 中初始化它 并在 onPause onStop 和 onDestroy 中调用 close 它在 onResume 中重新初始化 它似乎运行得很好 但当我查看调试器时
  • AndEngine MenuScene - 无法单击按钮

    我有一个关于 android 和 andengine 的小问题 这是我的主菜单的源代码 AbstractScene is extending Scene public class MainMenuScene extends Abstract
  • Android - 存储对ApplicationContext的引用

    我有一个静态 Preferences 类 其中包含一些应用程序首选项和类似的内容 可以在那里存储对 ApplicationContext 的引用吗 我需要该引用 以便我可以在不继承 Activity 的类中获取缓存文件夹和类似内容 你使用的
  • Android 的 Intent 和 Parcelable 对象

    为什么我需要打包我的对象 即使我只需将其发送到同一任务的另一个线程 实际上 我需要打开一个甚至可以在同一线程 主线程 上运行的活动 换句话说 为什么 Google 不提供一个 startActivity 版本 它采用通用对象广告参数而不是捆
  • Expresso 的 Android 测试首选项片段

    我在通过 Expresso 测试我的代码时遇到问题 我写了这段代码 public class SettingsActivity extends Activity Override protected void onCreate Bundle
  • 以 HTML 格式发送电子邮件

    我想发送 HTML 格式的电子邮件 如下图所示 我怎样才能做到这一点 请帮我 提前致谢 String body new String table tr td br header td tr br br Get b Best Score b
  • TextView.setMaxLines 不起作用?

    在我的应用程序中 我有一个屏幕 其中显示一些文本 然后显示一张照片 文本的长度是可变的 有时根本没有 有时很多 所以我想对其进行设置 以便文本永远不会占用超过几行 但可以滚动 为下面的图像留下足够的空间 我这部分的视图组件是以编程方式创建的
  • 了解应用程序在后台时何时收到 Firebase 消息

    我知道这个标题有同样的问题 但不幸的是它没有得到正确的回答 它被接受了 here https stackoverflow com questions 37711082 how to handle notification when app
  • XML 配置中的 screenName 不起作用

    我刚刚在我的应用程序中添加了对 Google Analytics 分析 的支持 但我无法

随机推荐

  • 使用 v4l2loopback 和 EDSDK Liveview 进行佳能 DSLR 视频环回?

    我想使用 DSLR 相机作为视频输入 例如在 Linux 和 Android 下进行 Skype Google talk 是否可以使用 v4l2loopback 和 Canon EDSDK 创建视频环回 如何将实时取景缓冲区从摄像机传输到视
  • 为什么 DataContractSerializer 不支持属性?

    我根据客户的文档创建 xsd 并且所有 xsd 都有属性 我一直在使用 xsd exe 从 xsd 生成类 但我读到 DataContractSerializer 不支持属性 为什么不 这是否意味着我只能有一个只有元素的soap xml 文
  • 关于 TypeScript 的 noUnusedParameters 编译器选项的说明

    在 GitHub 上输入任何内容之前 我试图确定这实际上是否是一个错误 With noUnusedParameters启用后 TypeScript 编译器会出现如下错误 const foo one two three foo forEach
  • 生日显示为去年的年龄?

    我正在测试一个我想在其中使用它的网站的 JavaScript 片段 基本上 当页面加载我的年龄时执行的函数 我是在规定的出生日期之外做这件事的 我在使用birthDate变量时注意到一个错误 不确定为什么会发生 当birthDate月份比当
  • Doctrine ORM 内存问题

    问题 运行使用下面 Factory 类中的 Doctrine 的守护程序服务时 会出现内存问题 当守护进程服务启动时 它运行大约 175MB 一天后大约是 250MB 再过一天就达到 400MB 我正在寻找导致内存增加的原因以及如何降低内存
  • 将java库包含到自己的库中

    我为自己创建了一个小框架 我想在多个项目中使用它 我还希望分布式 jar 文件包含所有外部库 以便我的项目只需要包含我的库即可访问所有外部库 我需要这个来简化外部库的更新 所以我把它放在我的 build xml 中 它将 dist lib
  • 如何使用加特林检查 If 方法?

    记录在案here https gatling io docs current cheat sheet 加特林checkIf方法用于条件检查 它不可用于ScenarioBuilder的流畅 API 但我可以在CheckSupport班级 我在
  • 如何将在线 CSV 数据插入 SQL Server 数据库?

    我需要每天从在线可用的 csv 执行数据加载 例如http www supplier com products csv http www supplier com products csv一旦我将 csv 转储到 sql 表中 我就可以进行
  • 如何枚举es6类方法[重复]

    这个问题在这里已经有答案了 如何枚举 ES6 类的方法 如同Object keys 这是一个例子 class Callbacks method1 method2 const callbacks new Callbacks callbacks
  • 为什么 &&、&、|| 的输出不同?

    这是代码段 你能解释一下为什么输出不同 1 public static ShortCkt public static void main String args int i 0 boolean t true boolean f false
  • 使用 Makefile 在编译中排除源文件

    是否可以使用 Makefile 中的通配符函数在编译过程中排除源文件 就像有几个源文件一样 src foo cpp src bar cpp src 然后在我的 makefile 中 SRC FILES wildcard src cpp 但我
  • 以编程方式滚动离子段

    有什么办法可以控制分段的滚动吗 在我的情况下 滑块和段相互依赖 当您滑动幻灯片时 溢出段不会滑动 但将正确选择活动段 我的视图和控制器代码
  • 如何撤销 JWT 令牌?

    我正在使用 Spring Security OAuth2 和 JWT 令牌 我的问题是 如何撤销 JWT 令牌 正如这里提到的http projects spring io spring security oauth docs oauth2
  • 如何在 Node.js 中创建函数

    我正在使用 Firebase 函数创建 API 同时我使用 Firebase Firestore 作为我的数据库 我正在使用 Node js 来创建该程序 我想知道如何在 Node js 中创建函数 我将多次调用代码 因为我已经习惯了 Ja
  • 如何更改测试资源管理器的持续时间计时器,使其对于长(>1 秒)测试更有用?

    我在 Visual Studio 2013 中编写了一系列测试用例 这些测试用例通过 Visual Studio 的内置测试资源管理器运行 这些不是单元测试 因此它们都运行至少几秒钟 由于测试内容的性质 其中一些测试的运行时间甚至可能超过
  • Mac 上有什么好的 MongoDB 数据库管理应用程序吗?类似于 Sequel Pro? [复制]

    这个问题在这里已经有答案了 寻找一个可视化 mongodb 中的集合和文档的 GUI 网络上有许多可用的工具 罗博蒙戈 https robomongo org 是最好的和最著名的 Mongo客户端 http www mongoclient
  • 如何使用 Boost::Python 公开原始字节缓冲区?

    我有第三方 C 库 其中一些类方法使用原始字节缓冲区 我不太确定如何在 Boost Python 中处理它 C 库头类似于 class CSomeClass public int load unsigned char pInBufferDa
  • DynamoDB 如何同时支持 Key-Value 和 Document 数据库属性

    根据 DynamoDB 的文档 它支持 NoSQL 的键值和面向文档的属性 即使其他 NoSQL 数据库仅属于一种类型 键值 文档 图形或面向列 它还说 Amazon DynamoDB 基于 Dynamo 的原则构建 3 是 AWS 基础设
  • 必须调用“render :layout => false”才能在 Rails 2.3.3 中正确渲染 js.erb 模板

    我正在运行最新的 Rails 2 3 stable 分支 当前为 2 3 3 我正在使用 JQuery 将 AJAX 请求发布到我的 创建 操作 其中有以下块 respond to do format format js end 我创造了c
  • 如何设置应用内购买(非消耗品)?

    我正在使用一些在线教程在我的应用程序中实现应用程序内购买 但该教程适用于消费品应用内购买 但就我而言 用户只需要购买一次 我修改了代码 在购买应用内购买后禁用 购买按钮 现在一切正常 但问题是 如果我关闭并打开应用程序 购买按钮 就会启用