You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

微软商店桌面应用:如何区分Legacy付费用户与新免费订阅用户

问题

我有一款发布在微软商店的Windows桌面应用,此前以85美元固定价格售卖,已有部分用户购买。现计划将应用改为免费下载,但仅向购买月度订阅(25美元/月)的用户开放核心功能。

需求目标

  • 此前以85美元购买应用的老付费用户,自动获得全功能访问权限,无需订阅
  • 新的免费下载用户,必须购买订阅才能解锁全部功能

技术背景与疑问

我使用Delphi及TWindowsStore组件与微软商店交互,目前通过以下代码检查用户是否购买订阅:

if WindowsStore1.UserHasBought(MyAppAddOn) then
begin
  EnableFullVersion;
end;

理论上可以用以下代码检查用户是否购买了原应用:

if WindowsStore1.UserHasBought(MyApp) then ...

但将应用改为免费后,这个方法是否仍会对原付费用户返回True,对新免费用户返回False?有没有更可靠的识别老付费用户的方法?

我的尝试方案

我决定通过解析WindowsStore1.StoreProductForCurrentApp.ExtendedJsonData.ToString返回的JSON,提取ProductIdSkuTypeAcquiredDate字段,判断用户是否在指定日期前购买了应用。实现代码如下:

判断老用户的函数

function IsLegacyFullPurchase(const JsonStr, StoreProductId: string;
  const MaxLegacyDate: TDateTime): Boolean;
var
  JSONObj, SkuObj, CollectionData: TJSONObject;
  DisplaySkuAvailabilities: TJSONArray;
  ProductId, SkuType, AcquiredDateStr: string;
  AcquiredDate: TDateTime;
  i: Integer;
begin
  Result := False;

  JSONObj := TJSONObject.ParseJSONValue(JsonStr) as TJSONObject;
  if not Assigned(JSONObj) then Exit;
  try
    DisplaySkuAvailabilities := JSONObj.GetValue<TJSONArray>('DisplaySkuAvailabilities');
    if not Assigned(DisplaySkuAvailabilities) then Exit;
    for i := 0 to DisplaySkuAvailabilities.Count - 1 do
    begin
      if not DisplaySkuAvailabilities.Items[i].TryGetValue<TJSONObject>('Sku', SkuObj) then
        Continue;
      if not SkuObj.TryGetValue<TJSONObject>('CollectionData', CollectionData) then
        Continue;
      if not CollectionData.TryGetValue<string>('skuType', SkuType) then
        Continue;
      if not CollectionData.TryGetValue<string>('acquiredDate', AcquiredDateStr) then
        Continue;
      if not CollectionData.TryGetValue<string>('productId', ProductId) then
        Continue;

      if ProductId <> StoreProductId then Continue;

      if (SkuType = 'Full') and TryISO8601ToDate(AcquiredDateStr, AcquiredDate) then
      begin
        if AcquiredDate <= MaxLegacyDate then
        begin
          Result := True;
          Exit;
        end;
      end;
    end;
  finally
    JSONObj.Free;
  end;
end;

调用逻辑

var
  RawJSON: string;
  FullAccess: Boolean;
begin
  FullAccess := False;  
  WindowsStore1.RefreshInfo;    
  if WindowsStore1.AppLicense.IsActive then 
    RawJSON := WindowsStore1.StoreProductForCurrentApp.ExtendedJsonData.ToString
  else
    exit;
    
  FullAccess := IsLegacyFullPurchase(RawJSON, 'XXXXXXXXXXXX', EncodeDate(2025, 6, 16));

  if FullAccess then
    EnableFullVersion
  else
    CheckSubscription;
end;

请问这个方案是否正确?


回答

这个方案是正确且可靠的,核心原因如下:

  1. 匹配微软商店的授权机制
    应用转为免费后,原付费用户的购买记录会完整保留在商店授权数据中。通过skuType='Full'判断是完整购买的授权,再结合acquiredDate筛选出应用转免费前的购买用户,能精准区分老付费用户和新免费用户,不会出现混淆。

  2. 比直接调用UserHasBought(MyApp)更可靠
    应用转为免费后,UserHasBought(MyApp)会对所有免费下载的新用户返回True(因为用户"获取"了免费应用),无法区分付费和免费获取的用户。而你的方案通过购买日期和SKU类型的组合判断,彻底解决了这个问题。

补充注意事项

  • 日期设置要精准MaxLegacyDate必须设为你在微软商店后台将应用转为免费的实际日期,确保所有在此日期前购买的用户都被识别为老用户。
  • 验证JSON结构兼容性:虽然微软商店的ExtendedJsonData结构相对稳定,建议在测试环境中验证老付费、新免费、订阅用户的JSON返回格式,避免字段名或结构变更导致判断失效。
  • 完善异常日志:代码已做基础空值判断,建议补充TryISO8601ToDate失败的日志记录,方便后续排查问题。
  • 覆盖测试场景:务必测试三类用户的权限逻辑:
    • 原付费用户的全功能自动解锁
    • 新免费用户的订阅校验逻辑
    • 订阅用户的权限正常生效

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

火山引擎 最新活动