You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Delphi 12.1中通过TWindowsStore组件实现应用内订阅内购?

在Delphi 12.1中使用TWindowsStore组件实现订阅类内购的正确方法

问题背景

我有一款已发布至微软商店的应用,包含一个订阅类内购项。根据官方文档说明:

目前不支持通过商店直接向客户销售订阅,订阅仅适用于数字产品的应用内购买

因此需要在应用内手动实现该内购功能。找到一份示例代码作为开发起点,但该代码会触发异常,现寻求正确的实现方式。

原示例代码

function TForm1.PurchaseItem(Item: string) : string;
begin
  for var i := 0 to WindowsStore1.AppProducts.Count - 1 do
    if TWindowsString.HStringToString(WindowsStore1.AppProducts[i].InAppOfferToken) = Item then begin
      BuyProduct(WindowsStore1.AppProducts[i]);
      exit;
    end;
end;

procedure TForm1.BuyProduct(Product: IStoreProduct);
begin
  try
    var status := WindowsStore1.PurchaseProduct(Product);
    if status = StorePurchaseStatus.Succeeded then 
    begin
      EnableFullVersion;
    end
    else begin
      //;
    end;
  except
    On e : Exception do
      //;
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  PurchaseItem('MyAddon');
end;

正确实现步骤与代码

1. 初始化与异步加载订阅产品

同步加载产品易引发异常,需通过异步方式完成初始化与产品加载:

var
  FSubscriptionProduct: IStoreProduct;

procedure TForm1.FormCreate(Sender: TObject);
begin
  // 初始化商店组件(必须在UI线程执行)
  WindowsStore1.Initialize;
  // 异步加载应用内所有产品(含订阅)
  WindowsStore1.LoadAppProductsAsync;
end;

// 产品加载完成的事件回调
procedure TForm1.WindowsStore1AppProductsLoaded(Sender: TObject;
  const Products: TArray<IStoreProduct>);
begin
  FSubscriptionProduct := nil;
  // 遍历找到目标订阅产品
  for var Product in Products do
  begin
    if TWindowsString.HStringToString(Product.InAppOfferToken) = 'MyAddon' then
    begin
      FSubscriptionProduct := Product;
      Break;
    end;
  end;
end;

2. 异步发起订阅购买并处理结果

订阅购买必须使用异步方法,同步调用会导致线程异常,同时完善状态处理:

procedure TForm1.Button1Click(Sender: TObject);
begin
  if not Assigned(FSubscriptionProduct) then
  begin
    ShowMessage('订阅产品未加载,请稍后重试');
    Exit;
  end;
  // 异步发起订阅购买请求
  WindowsStore1.PurchaseProductAsync(FSubscriptionProduct);
end;

// 购买完成的事件回调
procedure TForm1.WindowsStore1PurchaseCompleted(Sender: TObject;
  const Status: StorePurchaseStatus; const Receipt: string);
begin
  case Status of
    StorePurchaseStatus.Succeeded:
      begin
        // 必须验证订阅收据,防止本地篡改
        if ValidateSubscriptionReceipt(Receipt) then
          EnableFullVersion
        else
          ShowMessage('订阅验证失败,请检查网络');
      end;
    StorePurchaseStatus.AlreadyPurchased:
      ShowMessage('您已拥有该订阅');
    StorePurchaseStatus.NotPurchased:
      ShowMessage('购买已取消');
    StorePurchaseStatus.NetworkError:
      ShowMessage('网络异常,请检查连接');
    else
      ShowMessage('购买失败,错误码:' + Ord(Status).ToString);
  end;
end;

// 订阅收据验证逻辑(需对接微软商店API实现)
function TForm1.ValidateSubscriptionReceipt(const Receipt: string): Boolean;
begin
  // 实际需调用微软商店收据验证接口,解析订阅有效期等信息
  // 此处为简化示例,仅判断收据非空
  Result := Receipt <> '';
end;

3. 启动时查询订阅状态

应用启动后需主动查询用户当前订阅状态,确保已订阅用户正常使用功能:

procedure TForm1.FormShow(Sender: TObject);
begin
  // 异步查询用户已购买的产品(含订阅)
  WindowsStore1.GetUserCollectionAsync;
end;

// 用户已购产品加载完成的事件回调
procedure TForm1.WindowsStore1UserCollectionLoaded(Sender: TObject;
  const Products: TArray<IStoreProduct>);
begin
  var HasValidSubscription := False;
  for var Product in Products do
  begin
    if TWindowsString.HStringToString(Product.InAppOfferToken) = 'MyAddon' then
    begin
      HasValidSubscription := True;
      Break;
    end;
  end;

  if HasValidSubscription then
    EnableFullVersion
  else
    DisableFullVersion;
end;

关键注意事项

  • 强制使用异步操作:所有与微软商店交互的操作(加载产品、购买、查询订阅)必须用异步方法,避免同步调用导致的UI阻塞或线程异常。
  • 精准异常捕获:优先捕获EStoreException这类商店专属异常,而非通用Exception,便于定位错误原因。
  • 严格收据验证:必须通过微软官方API验证订阅收据,不能仅依赖本地状态判断,防止破解。
  • 后台配置匹配:确保微软商店后台的订阅内购项InAppOfferToken与代码中使用的完全一致。

内容的提问来源于stack exchange,提问作者Taras

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 21:24:50