如何在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
相关产品推荐
相关产品推荐

