微软商店桌面应用:如何区分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,提取ProductId、SkuType、AcquiredDate字段,判断用户是否在指定日期前购买了应用。实现代码如下:
判断老用户的函数
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;
请问这个方案是否正确?
这个方案是正确且可靠的,核心原因如下:
匹配微软商店的授权机制
应用转为免费后,原付费用户的购买记录会完整保留在商店授权数据中。通过skuType='Full'判断是完整购买的授权,再结合acquiredDate筛选出应用转免费前的购买用户,能精准区分老付费用户和新免费用户,不会出现混淆。比直接调用
UserHasBought(MyApp)更可靠
应用转为免费后,UserHasBought(MyApp)会对所有免费下载的新用户返回True(因为用户"获取"了免费应用),无法区分付费和免费获取的用户。而你的方案通过购买日期和SKU类型的组合判断,彻底解决了这个问题。
补充注意事项
- 日期设置要精准:
MaxLegacyDate必须设为你在微软商店后台将应用转为免费的实际日期,确保所有在此日期前购买的用户都被识别为老用户。 - 验证JSON结构兼容性:虽然微软商店的
ExtendedJsonData结构相对稳定,建议在测试环境中验证老付费、新免费、订阅用户的JSON返回格式,避免字段名或结构变更导致判断失效。 - 完善异常日志:代码已做基础空值判断,建议补充
TryISO8601ToDate失败的日志记录,方便后续排查问题。 - 覆盖测试场景:务必测试三类用户的权限逻辑:
- 原付费用户的全功能自动解锁
- 新免费用户的订阅校验逻辑
- 订阅用户的权限正常生效
内容的提问来源于stack exchange,提问作者Taras




