应用内结算,签名验证失败

2024-03-15

当我尝试获取订阅时,出现以下错误:

签名认证失败。 签名与数据不匹配。 应用内结算警告:购买签名验证FAILED。不添加项目。

我的代码是:

String base64EncodedPublicKey = MY_KEY;

        // compute your public key and store it in base64EncodedPublicKey
        mHelper = new IabHelper(this, base64EncodedPublicKey);

        mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
            public void onIabSetupFinished(IabResult result) {
                if (!result.isSuccess()) {
                    // Oh noes, there was a problem.
                    MyDialogFragment alertDialog_generalError = MyDialogFragment.newInstance(getString(R.string.dialog_alert),getString(R.string.error_general));
                    alertDialog_generalError.show(getSupportFragmentManager(), DIALOG_GENERALERROR);
                } //End if   
                mHelper.queryInventoryAsync(mGotInventoryListener);
            }
        });  

//************************************************* 

//Get App price
IabHelper.QueryInventoryFinishedListener mQueryFinishedListener = new IabHelper.QueryInventoryFinishedListener() {
    public void onQueryInventoryFinished(IabResult result, Inventory inventory)   {
        if (result.isFailure()) {
            // handle error
            MyDialogFragment alertDialog_generalError = MyDialogFragment.newInstance(getString(R.string.dialog_alert),getString(R.string.error_general));
            alertDialog_generalError.show(getSupportFragmentManager(), DIALOG_GENERALERROR);
            return;
        }//End if
        String premiumPrice = inventory.getSkuDetails(SKU_PREMIUM).getPrice();
        btnPrice.setText(getResources().getString(R.string.btn_suscription) + " " + premiumPrice);
        myProfile.setPriceApp(premiumPrice);
    }
};

//  //************************************

@Override
public void inapp() {
    //myProfile.getGUID()
    //mHelper.launchPurchaseFlow(this, SKU_PREMIUM, RC_REQUEST, mPurchaseFinishedListener, myProfile.getGUID() );
    mHelper.launchSubscriptionPurchaseFlow(this, SKU_PREMIUM, RC_REQUEST, mPurchaseFinishedListener, myProfile.getGUID() );
}

//************************************
@Override
public void getPrice(Button btnPrice) {
    Log.i(LOGTAG, "getPrice");
    this.btnPrice = btnPrice;
    List additionalSkuList = new ArrayList();
    additionalSkuList.add(SKU_PREMIUM);
    mHelper.queryInventoryAsync(true, additionalSkuList, mQueryFinishedListener);   
}

//************************************************

// Callback for when a purchase is finished
IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener = new IabHelper.OnIabPurchaseFinishedListener() {
    public void onIabPurchaseFinished(IabResult result, Purchase purchase) {


        // if we were disposed of in the meantime, quit.
        if (mHelper == null) return;

        if (result.isFailure()) {
            if (result.getResponse() != -1005){
                MyDialogFragment alertDialog_errorInApp = MyDialogFragment.newInstance(getString(R.string.dialog_alert),getString(R.string.error_inApp));
                alertDialog_errorInApp.show(getSupportFragmentManager(), DIALOG_GENERALERROR);  
            }
            return;
        }
        if (!verifyDeveloperPayload(purchase)) {
            MyDialogFragment alertDialog_errorInApp = MyDialogFragment.newInstance(getString(R.string.dialog_alert),getString(R.string.error_inApp));
            alertDialog_errorInApp.show(getSupportFragmentManager(), DIALOG_GENERALERROR);  
            return;
        }

        myProfile.setIsPremium(1);
        loginPrefsEditor.putInt("IsPremium", 1);    

    }
};

//**********************************

//User PREMIUM or NOT PREMIUM
// Listener that's called when we finish querying the items and subscriptions we own
IabHelper.QueryInventoryFinishedListener mGotInventoryListener = new IabHelper.QueryInventoryFinishedListener() {
    public void onQueryInventoryFinished(IabResult result, Inventory inventory) {
        // Have we been disposed of in the meantime? If so, quit.
        Log.i(LOGTAG, result.getMessage());
        //if (mHelper == null) return;

        //Is it a failure?
        if (result.isFailure()) {
            MyDialogFragment alertDialog_generalError = MyDialogFragment.newInstance(getString(R.string.dialog_alert),getString(R.string.error_general));
            alertDialog_generalError.show(getSupportFragmentManager(), DIALOG_GENERALERROR);
            return;
        }

        /*
         * Check for items we own. Notice that for each purchase, we check
         * the developer payload to see if it's correct! See
         * verifyDeveloperPayload().
         */

        // Do we have the premium upgrade?
        Purchase premiumPurchase = inventory.getPurchase(SKU_PREMIUM);
        mIsPremium = (premiumPurchase != null && verifyDeveloperPayload(premiumPurchase));
        if (mIsPremium == true){
            myProfile.setIsPremium(1);
            loginPrefsEditor.putInt("IsPremium", 1);
        }else{
            loginPrefsEditor.putInt("IsPremium", 0);
            myProfile.setIsPremium(0);
        }//End if-else
    }
};

//****************************************

/** Verifies the developer payload of a purchase. */
boolean verifyDeveloperPayload(Purchase p) {
    String payload = p.getDeveloperPayload();
    if (!payload.equals(myProfile.getGUID())){
        return false;
    }else{
        return true;
    }//End if-else
}   

我从控制台开发人员那里获得了 base64EncodedPublicKey,并使用导出向导签署了我的项目。


如果您曾经使用测试 SKU 之一完成购买流程(android.test.purchased...)。这些购买不是真实的,因此它们没有签名,但当您尝试使用 IAB 执行任何操作(例如查询库存)时,它们是返回结果的一部分。不幸的是,一旦结果中的某些内容未能通过这些虚假购买所进行的验证,IAB 就会退出。

有两种方法可以解决这个问题。首先,使验证在测试中始终通过。最安全的方法是改变verifyPurchase in IABUtils>Security仅在调试版本上返回 true。

public static boolean verifyPurchase(String base64PublicKey, String signedData, String signature) {
    if (BuildConfig.DEBUG) {
        return true;
    }
    if (TextUtils.isEmpty(signedData) || TextUtils.isEmpty(base64PublicKey) ||
            TextUtils.isEmpty(signature)) {
        Log.e(TAG, "Purchase verification failed: missing data.");
        return false;
    }

    PublicKey key = Security.generatePublicKey(base64PublicKey);
    return Security.verify(key, signedData, signature);
}

解决此问题的第二种方法是不对这些虚假购买进行验证。更好的是:也只在调试版本上执行此操作。一种方法是更改verifyPurchase接受 SKU 并将其用作支票的一部分。然后,您必须更改 IabHelper 才能使用这个额外的参数。

public static boolean verifyPurchase(String base64PublicKey, String signedData, String signature, String sku) {
    if (BuildConfig.DEBUG) {
        if (skuMatchesTestingSku(sku)) {
            return true;
        }
    }

    ...
}

private static boolean skuMatchesTestingSku(String sku) {
    return sku.equals("android.test.purchased") ||
            sku.equals("android.test.canceled") ||
            sku.equals("android.test.refunded") ||
            sku.equals("android.test.item_unavailable");
}

这非常混乱,但由于应用内计费的实施方式,我们无能为力。

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

应用内结算,签名验证失败 的相关文章

  • 如何在点击时从 webview 获取 URL

    我怎样才能获得 点击的URL webview在其点击事件上 Override public void onClick View v if v getId R id webview Here i want to get clicked url
  • Android USB_DEVICE_ATTACHED 持久权限

    如何让 Android 在每次重新连接 USB 设备时都不再请求权限 我想让它记住 USB 设备的 默认使用 复选标记 这样我就不必每次都向同一设备授予权限 我以编程方式检测 USB 设备 Android 手机 何时连接到我的主机设备 An
  • 如何在 Android 中使用 KSoap 2

    我刚刚发现 ksoap2 在 Android 应用程序中使用我自己的 asp net Web 服务 我在互联网上发现了一些很棒的资源 并且我已经在 Android 应用程序中实现了我的网络服务 以下是我使用的网络服务的响应 HTTP 1 1
  • CursorAdapter 破坏了 CHOICE_MODE_MULTIPLE 选项

    我有一个ListFragment 我在其中添加一个CursorAdapter to my ListView 并且我希望能够单击几行以使用上下文操作栏 我使用 SherlockActionbar 当我使用一个简单的ArrayAdapter 但
  • 如何从 BroadcastReceiver 刷新 ListView?

    如果我打电话notifyDataSetChanged 在与我的 ListView 关联的自定义适配器上 所有视图都应该自行刷新 getView 将被调用 现在我有一个正在监听事件的 BroadcastReceiver 当事件触发时 List
  • 设备锁定时,互联网音乐播放器无法加载歌曲(打瞌睡模式?)

    我正在构建一个音乐播放器 可以播放互联网上的歌曲 我注意到 通常 当一首歌曲结束并且必须加载另一首歌曲时 应用程序不会播放下一首歌曲 我等啊等 终于决定解锁手机以了解发生了什么 令人惊讶的是 设备解锁后立即开始播放以下歌曲 第一次我以为这只
  • 如何在android中对Log.e进行单元测试?

    我需要执行单元测试 在应用程序中发生特定情况时 我需要检查是否记录错误消息 try do something catch ClassCastException IndexOutOfBoundsException e Log e INFOTA
  • 支持多屏幕[关闭]

    很难说出这里问的是什么 这个问题是含糊的 模糊的 不完整的 过于宽泛的或修辞性的 无法以目前的形式得到合理的回答 如需帮助澄清此问题以便重新打开 访问帮助中心 help reopen questions 支持多个屏幕和不同的屏幕密度必须注意
  • Android 应用程序 Azure 依赖项 gradle 构建时出错

    我在 Android Studio 2 3 3 的 Gradle 同步中收到以下错误 错误 模块 com microsoft azure azure mobile android 3 3 0 依赖于一个或多个 Android 库 但它是一个
  • OnSharedPreferenceChangeListener 未调用 #2

    好吧 我开始从 Google 的 android 实现这个可怕的代码 未调用 OnSharedPreferenceChangeListener 这是我的代码 你能建议一下吗 类定义 private SharedPreferences sPr
  • com.google.android.gms.games.GamesClient 无法解析

    我正在尝试使用 google play 游戏服务开发实时多人游戏 并下载了示例 ButtonClicker2000 但 Eclipse ADK 一直抱怨 com google android gms games GamesClient 无法
  • Android从Activity调用Service中的方法

    我想调用一个方法Service对象来自一个Activity对象 但是我发现不可能从MainActivity通常情况下 我希望我的代码能更好地解释我的意思 Service public class Timer extends Service
  • 从壁纸中获取颜色? - 安卓

    如何找到当前壁纸的 平均 颜色并将该颜色设置为我的小部件上的布局 我正在尝试做的一个例子 这是 AccuWeather 上的设置 您可以使用WallpaperManager getWallpaperColors https develope
  • 调用replace()方法后片段闪烁/闪烁

    我有一个MainActivity 应该在两个片段之间切换 内容和设置 扩展PreferenceFragmentCompat 一切工作正常 但最近我实施了Dagger 2依赖注入 我的设置片段开始闪烁 当您按下底部导航栏上的设置项时 有时会出
  • 如何检查Android应用程序是否第一次打开

    我想在用户第一次打开应用程序时有一个弹出窗口 如何查看 获取应用程序被打开的次数 请帮忙 多谢 当您的应用程序启动时 在onCreate 方法 您可以检查 SharedPreference 是否存在 如果没有 则这是该应用程序第一次启动 然
  • Android 是否可以同时使用前后摄像头[重复]

    这个问题在这里已经有答案了 我想同时使用设备的前置和后置摄像头 在我的应用程序中 屏幕的前半部分将显示后置摄像头的预览 屏幕的下半部分将显示前置摄像头的预览 我尝试过设置两个不同的相机预览 但是当我打开应用程序时 屏幕的前半部分 显示后置相
  • 获取 Search.List 中的 ViewCount - Youtube 数据 API v3

    最近 我与youtube API v3 for Android I use 搜索列表 https developers google com youtube v3 docs search list当我想从关键字检 索视频列表时 我可以从结果
  • Android 多用户支持(4.2 中的新功能)对服务器端数据模型(例如 android_id)的影响

    Google 刚刚发布了 Android 4 2 其中支持单个设备上的多个用户配置文件 http developer android com about versions android 4 2 html MultipleUsers htt
  • Activity 在 Android 上创建两次

    首先 我是 Android 开发新手 所以请耐心等待 我将从用户界面开始 我有一个按钮 一旦您点击它 就会启动一个活动以获取结果 public class GUIActivity extends Activity Override publ
  • Android:如何获取小数点后的两位数?不想截断值

    如何获取小数点后仅两位数的双精度值 例如 如果 a 190253 80846153846 那么结果值应该像 a 190253 80 尝试 我尝试过这个 public static DecimalFormat twoDForm new Dec

随机推荐

  • 更新被拒绝,因为当前分支的提示位于提示后面:其远程对应分支。集成远程更改(例如[重复]

    这个问题在这里已经有答案了 更新被拒绝 因为当前分支的尖端落后 提示 它的远程对应物 集成远程更改 我试图将本地 octopress 博客推送到远程分支 但上面的说法是错误的 另一个是 我是否必须管理或推送本地更改来源或起源分支 当我执行
  • 如何在 React JSX 中除最后一个元素之外的每个元素后面添加 array.map 中的逗号

    如何在数组的每个元素后面添加尾随逗号以创建如下列表 INV INV INV INV 请注意 最后一个元素没有尾随逗号 目前正在迭代列表array map var List React createClass render function
  • 使用蓝牙耳机启动语音识别无法正常工作

    我需要使用具有语音识别功能的蓝牙耳机 在 S3 S4 和 Samsung Grand 等某些设备上几乎可以正常工作 然而 当我在 Nexus 7 上尝试同样的操作时 我得到了 BluetoothHeadsetServiceJni Faile
  • C++中bool数据类型的比较

    The bool数据类型通常表示为0 as false and 1 as true 然而 也有人说true值可以用除以下以外的值表示1 如果后面的语句是true 那么下面的表达式可能是不正确的 bool x 1 if x 1 Do some
  • 将图标与按钮标签内的文本顶部对齐

    如何将按钮标签内的图标与文本顶部对齐 它当前位于文本的左侧 我不知道怎么办 这是代码 div class nav div
  • VS2012 中的 BeforeBuild 和其他目标发生了什么?

    我试图让一些预构建步骤在 Visual Studio 2012 中的 C 项目中工作 但它们不会被调用 虽然我很确定相同的技术在 Visual Studio 2010 中也可以使用 命令行构建的行为完全相同 这是项目文件的结尾 该文件是使用
  • json_encode() 返回 false

    这是我第一次面对数组结果布尔值的 var dumping json encode 我有一个由反序列化产生的数组 我 var dumped 它并确保它是一个有效的数组 结果如下 这只是一部分 而不是整个调试视图 array size 3 id
  • 如何直接访问azure应用程序服务实例

    我是天蓝色的新手 我有一个 Asp Net MVC 应用程序托管在 azure 应用程序服务 上 有两个实例 我的应用程序使用本地缓存 有时我需要清除这个缓存 但问题是 当我清除缓存时 我实际上只针对一个特定实例执行此操作 而其他实例仍然保
  • Symfony2创建服务[关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 symfony2 文档中曾经有关于如何创建服务 my mailer 的操作方法 但我似乎无法在任何地方
  • MySQL 8.0.11 由于 caching_sha2_password 连接错误

    当我尝试连接到 MySQL Workbench 上的服务器时 收到错误消息 您的连接尝试无法以 localhost 3306 身份从主机到服务器的用户 root 认证插件caching sha2 password无法加载 指定的模块无法找到
  • WiX 安装程序:使用 xslt 和 heat.exe 来更新属性

    我正在尝试为 Windows 服务创建 WiX 安装程序 并且我读到需要将所有文件的 KeyPath 设置为 no WiX 脚本中的 exe 除外 我目前正在使用 Heat exe 生成目录和文件结构 这是我的命令 WIX bin heat
  • 绘制路径大于最大位图尺寸

    我想画一条比canvas getMaximumBitmapWidth and or canvas getMaximumBitmapHeight 在可缩放的视图内 特别是在较旧的设备 Android 9 及更早版本 上 这会导致 路径太大而无
  • 当标签已存在于远程时​​,Git 强制推送标签

    我已经将标签推送到遥控器上 当另一个用户创建相同的标签并尝试推送时 推送将失败 因为该标签已存在于远程上 但我想如果我这么做了 f force tag push 它应该可以工作 但我所看到的并非如此 我想我必须这样做 Create tag
  • 是否应该迁移变更集的用户名和时间戳?

    以下文字关于OpsHub 迁移实用程序页面 https visualstudiogallery msdn microsoft com 28a90a17 d00c 4660 b7ae 42d58315ccf2表示用户名和时间戳将嵌入到迁移的变
  • 在 BIDS 中使用存储过程作为 OLE DB 源

    我正在测试 SSIS 包和存储过程 因为我只是一个初学者 我需要做的是使用在源数据库上安装的存储过程来返回数据集 然后我需要一个 ssis 包来使用存储过程返回的数据集作为 OLE DB 源来填充第二个目标表 基本上我有两张桌子 测试源 测
  • 可变参数模板的可扩展性

    我正在使用 C 11 开发一个大规模软件基础设施 该基础设施广泛使用了可变参数模板 我的问题如下 这种方法的可扩展性如何 首先 可变参数模板可以采用的参数数量是否有上限 其次 当使用许多参数时 并且 通过扩展 这些参数的许多组合将产生模板化
  • 在 Java 中用 Scala 中的 Option 包装返回 null 的方法?

    假设我有一个方法session get str String String但你不知道它会返回一个字符串还是一个 null 因为它来自 Java 在 Scala 中是否有更简单的方法来处理这个问题而不是session get foo null
  • 客户端加密的有效用例有哪些?

    我刚刚读到斯坦福大学 Javascript 加密库 http crypto stanford edu sjcl jsfiddle 示例 http jsfiddle net kRcNK 它完全用 JavaScript 支持 SHA256 AE
  • DICOM 和图像位置患者

    我试图弄清楚 DICOM 图像位置 0020 0032 是绝对坐标还是只是我拥有的任何切片方向的坐标 例如 我有两个平面 一个矢状平面和一个冠状平面 与 DICOM 标头中的 x y z 形式的相应图像位置 以毫米为单位 交错 我的问题是
  • 应用内结算,签名验证失败

    当我尝试获取订阅时 出现以下错误 签名认证失败 签名与数据不匹配 应用内结算警告 购买签名验证FAILED 不添加项目 我的代码是 String base64EncodedPublicKey MY KEY compute your publ