Flutter 颤振如何检查autorenewal订阅是否仍然有效

Flutter 颤振如何检查autorenewal订阅是否仍然有效,flutter,in-app-purchase,subscription,Flutter,In App Purchase,Subscription,我的应用有一个1个月的自动续费订阅。当用户单击“购买订阅”按钮时,我正在将购买日期保存到共享首选项。 然后,1个月后,我需要检查此订阅是否仍然有效。 那么我如何实现它呢?有几种方法可以做到这一点,但我不会在移动设备上这样做 在您要求的设备上 安装,启动时将缓存键值“Subscription”设置为true,maxAgeCacheObject:Duration(天数:30)。每次启动时,检查该密钥是否仍存在于缓存中。如果是,那么它仍然有效,否则它已经过期 使用FirebaseFunction的建议

我的应用有一个1个月的自动续费订阅。当用户单击“购买订阅”按钮时,我正在将购买日期保存到共享首选项。 然后,1个月后,我需要检查此订阅是否仍然有效。
那么我如何实现它呢?

有几种方法可以做到这一点,但我不会在移动设备上这样做

在您要求的设备上

安装,启动时将缓存键值“Subscription”设置为true,maxAgeCacheObject:Duration(天数:30)。每次启动时,检查该密钥是否仍存在于缓存中。如果是,那么它仍然有效,否则它已经过期

使用FirebaseFunction的建议解决方案

我建议设置一个后端来管理所有这些。这不是移动设备的任务。您可以从firebase获得一个唯一的设备id,它将返回订阅是否仍然有效。一个无服务器的函数应该可以实现这一点。伪步骤:

  • (在设备上)当应用程序启动时,生成guid并使用您的guid发出http post请求
  • (服务器)在无服务器功能中,保存向数据库发出请求的日期以及发送的唯一ID。如果您的id已经在DB中,则检查它是否过期(添加日期-当前日期)<30天。从函数返回true或false。如果仍然有效,则为True;如果无效,则为false
  • (在设备上)当您从函数接收到true时,将生成的id本地保存在磁盘上,然后继续执行您想要执行的操作。如果为false,则将用户锁定在外或显示您要处理的订阅

  • ==从2020年3月11日起更新

    您好,我可以看到这篇文章仍在阅读的人谁寻找一种方法,如何在颤振订阅工作。 2019年期间,我制作了两个应用程序,安装了数千次,用户可以在这两个平台上购买续费订阅。 直到2020年2月,我才开始使用Flitter团队提供的这个软件包,但是-没有办法获得要在iOS中取消订阅的用户的信息。这不是插件问题,而是进程的iOS方法。出于安全原因,我们应该实现自己的后端(顺便说一句,谷歌也建议这样做,但仍然保留了直接从应用程序检查状态的方式)

    所以,经过一些研究,我找到了制作后端和插件的人,他们是免费的,直到你这个月的收入少于10000美元。

    我已经在我的应用程序中实现了这个插件,它就像一个魔咒。有一些很好的方法可以让你在应用程序的任何一点上获得订阅状态。我要做一个例子和一篇文章,但不确定时间

    ====

    自2019年7月15日起更新。只是为了节省时间。下面给出了一个过时的支付插件的答案。在那之后,弗利特团队制作了插件 我建议使用它

    =====

    最好的方法是使用安全的后端服务器进行接收。 但是,可以直接在应用程序中检查状态。 所以,当用户尝试访问某些付费功能时,您可以检查他的订阅是否处于活动状态。下面是一个例子:

    使用类在某处创建文件

    import 'dart:io' show Platform;
    import 'package:flutter/services.dart';
    import 'package:flutter_inapp_purchase/flutter_inapp_purchase.dart';
    import 'dart:async';
    
    class SubcsriptionStatus {
    static Future<bool> subscriptionStatus(
      String sku,
      [Duration duration = const Duration(days: 30),
      Duration grace = const Duration(days: 0)]) async {
        if (Platform.isIOS) {
          var history = await FlutterInappPurchase.getPurchaseHistory();
    
          for (var purchase in history) {
            Duration difference =
            DateTime.now().difference(purchase.transactionDate);
            if (difference.inMinutes <= (duration + grace).inMinutes &&
                purchase.productId == sku) return true;
          }
          return false;
        } else if (Platform.isAndroid) {
          var purchases = await FlutterInappPurchase.getAvailablePurchases();
    
          for (var purchase in purchases) {
            if (purchase.productId == sku) return true;
          }
          return false;
        }
        throw PlatformException(
            code: Platform.operatingSystem, message: "platform not supported");
      }
    }
    
    导入“dart:io”展示平台;
    导入“包:flifter/services.dart”;
    进口“包装:颤振-inapp\u采购/颤振-inapp\u采购.dart”;
    导入“dart:async”;
    类子脚本状态{
    静态未来订阅状态(
    字符串sku,
    [持续时间=持续时间(天:30),
    持续时间宽限=常数持续时间(天数:0)])异步{
    if(Platform.isIOS){
    var history=await flatterinapppurchase.getPurchaseHistory();
    对于(历史上的var购买){
    持续时间差=
    DateTime.now()差异(purchase.transactionDate);
    如果(以分钟为单位的差值)设置状态(){
    userSubscribed=val;
    }));
    }
    }
    
    在变量userSubscribed中,状态为true或false。
    (请注意,您必须添加到项目中).

    是的,关于漏洞,有一种方法可以解决用户手动更改时间只是为了欺骗应用程序的问题,我想到的解决方案是让日期时间以这种方式来自服务器,无论用户是否更改日期和时间,你最终都会得到正确的时间框架。我希望这能有所帮助


    至于检查订阅是否已过期,只需按照@awaik give的步骤进行操作,此外,您可以向api发出请求,以存储购买订阅的日期时间和预期订阅过期的日期时间。我建议您将购买日期和预期日期保存在服务器中,而不是在用户设备上应用程序的缓存或数据目录将导致保存的数据丢失。祝您好运。

    请详细说明您的问题,以便获得良好的响应。这太笼统了。我在官方网站上发现了这些信息,可能对某些人有所帮助。通过应用商店和Android处理订阅账单验证收据:此软件包似乎有一个方法getAvailablePurchases,提供用户所做的所有购买(非消费品或尚未消费)服务器端解决方案是实现这一点的正确方法。如果没有这一点,则存在许多漏洞,如1)伪造收据2)购买后获得退款3)更改系统时间以继续订阅。等等。这里缺少的是检查收据的频率超过30天,以查看收据是否被取消/退款。@enc_life我同意。我同意提到“应用程序启动时…”因此,这将在每个会话中发生。您将在每个会话中发出请求。如果返回true,则您将继续,否则您将阻止用户。甚至可能会执行锁定,以便在用户执行订阅逻辑并完成之前,您不必再次执行请求。是的,关于检查每个应用程序启动的状态,您是对的。我是ng重新验证接收服务器端pe
    class _SubscriptionState extends State<Subscription> {
      bool userSubscribed;
      _SubscriptionState() {
      SubcsriptionStatus.subscriptionStatus(iapId, const Duration(days: 30), const 
      Duration(days: 0)).then((val) => setState(() {
      userSubscribed = val;
       }));
       }
    }