如何确定 Microsoft Store 订阅 add-on 的付款日期?
结论
app 无法查询 Microsoft Store 订阅每个月的实际扣款日期。
StoreProduct.IsInUserCollection、StoreContext.GetAppLicenseAsync() 等 API 返回的是订阅权益状态,包括权益当前是否有效、何时到期,但不包含扣款记录、支付结算时间或完整的续订历史。用户离线数月后再次上线时,app 无法通过 Microsoft Store API 还原离线期间每笔付款的实际日期。
可以查询哪些信息
通过 Windows.Services.Store API,可以检查订阅 add-on 当前是否有效,并读取许可证的到期时间:
using System;
using System.Threading.Tasks;
using Windows.Services.Store;
public sealed class SubscriptionStatus
{
public bool IsActive { get; init; }
public DateTimeOffset ExpirationDate { get; init; }
}
public static async Task<SubscriptionStatus> GetSubscriptionStatusAsync(
string addOnStoreId)
{
StoreContext context = StoreContext.GetDefault();
StoreAppLicense appLicense = await context.GetAppLicenseAsync();
if (appLicense.AddOnLicenses.TryGetValue(
addOnStoreId,
out StoreLicense license))
{
return new SubscriptionStatus
{
IsActive = license.IsActive,
ExpirationDate = license.ExpirationDate
};
}
return new SubscriptionStatus
{
IsActive = false,
ExpirationDate = DateTimeOffset.MinValue
};
}
这里的 ExpirationDate 是当前订阅权益的到期时间,并不是付款时间。续订失败、宽限期、取消订阅、退款以及 Microsoft Store 的账单处理流程都可能影响这个时间。
StoreSubscriptionInfo 中的 BillingPeriod 和 BillingPeriodUnit 只能说明订阅周期,例如每月一次,无法用来查询实际扣款日期。
推荐的实现方式
建议分别记录以下两类数据:
- Microsoft Store 提供的订阅权益状态;
- app 自己管理的 credit 发放和使用流水。
首次购买成功时,可以记录:
PurchaseObservedAt
InitialExpirationDate
StoreId
SkuStoreId
此后每次 app 在线,都重新获取许可证并保存一份权益快照:
CheckedAt
IsActive
ExpirationDate
例如:
public sealed class EntitlementSnapshot
{
public DateTimeOffset CheckedAt { get; init; }
public bool IsActive { get; init; }
public DateTimeOffset ExpirationDate { get; init; }
}
public static async Task<EntitlementSnapshot> CaptureSnapshotAsync(
string addOnStoreId)
{
SubscriptionStatus status =
await GetSubscriptionStatusAsync(addOnStoreId);
return new EntitlementSnapshot
{
CheckedAt = DateTimeOffset.UtcNow,
IsActive = status.IsActive,
ExpirationDate = status.ExpirationDate
};
}
如果新的 ExpirationDate 晚于上次保存的值,可以确认订阅权益已经延长。但这只能说明权益期限发生了变化,无法证明扣款发生在某个确切时刻,也无法可靠地拆分出用户离线期间每个月的付款日期。
credit 应如何处理
如果 credit 需要按订阅周期发放,建议使用自己的账期标识,避免重复同步造成重复发放:
UserId
SubscriptionId
PeriodKey
CreditGranted
GrantedAt
SourceExpirationDate
PeriodKey 可以表示业务定义的订阅周期,例如:
2026-08
每次发放前,先检查同一组 SubscriptionId + PeriodKey 是否已经存在。这样的幂等设计可以避免用户重复上线、设备时间变化或同步重试导致 credit 被多次发放。
如果用户连续离线多个周期,而业务规则要求”只有实际付款后才逐月发放”,那么客户端许可证状态不足以准确补发这些周期的 credit。此时需要调整业务规则,例如:
- 只按照当前已确认的有效权益发放 credit;
- 限制离线期间可累计的周期数;
- 要求用户定期联网验证;
- 通过自己的服务端保存每次观察到的权益变化。
即使使用服务端,也只能保存和核验 Microsoft Store 对外提供的权益信息,无法获得客户端 API 没有公开的逐笔扣款时间。
账单中的表述
app 可以展示自己记录的 credit 流水,例如”credit 发放时间”、“credit 使用时间”和”对应权益周期”,但不应把推算日期标记为”Microsoft 实际付款时间”。
如果必须向用户展示真实的扣款日期和金额,应引导用户查看 Microsoft 账户中的订单历史或账单记录。app 内可以明确区分:
订阅权益确认时间订阅权益到期时间credit 发放时间credit 使用时间
这些时间可以由 app 准确记录。Microsoft Store 的实际扣款时间无法通过当前的 app 内 Store API 获取。
备注:内容仅供参考。
