驱蚊app
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

147 line
4.9 KiB

  1. using System;
  2. using System.Collections.Generic;
  3. using Unity.Services.Core;
  4. using UnityEngine;
  5. using UnityEngine.Purchasing;
  6. using UnityEngine.Purchasing.Extension;
  7. public class IAPManager : MonoBehaviour, IDetailedStoreListener
  8. {
  9. public static IAPManager Instance { get; private set; } // 单例
  10. private IStoreController controller;
  11. private IExtensionProvider extensions;
  12. private string subscriptionId = "quewenYueKa";
  13. void Awake()
  14. {
  15. // 单例初始化
  16. if (Instance == null)
  17. {
  18. Instance = this;
  19. DontDestroyOnLoad(gameObject); // 可选:防止切换场景被销毁
  20. }
  21. else
  22. {
  23. Destroy(gameObject); // 避免重复创建
  24. }
  25. }
  26. async void Start()
  27. {
  28. await UnityServices.InitializeAsync(); // 初始化 UGS
  29. var builder = ConfigurationBuilder.Instance(StandardPurchasingModule.Instance());
  30. builder.AddProduct(subscriptionId, ProductType.Subscription);
  31. UnityPurchasing.Initialize(this, builder); // 使用新版接口
  32. }
  33. public void OnInitialized(IStoreController controller, IExtensionProvider extensions)
  34. {
  35. this.controller = controller;
  36. this.extensions = extensions;
  37. Debug.Log("IAP 初始化成功");
  38. }
  39. public void OnInitializeFailed(InitializationFailureReason error)
  40. {
  41. Debug.LogError("IAP 初始化失败: " + error);
  42. }
  43. public void OnInitializeFailed(InitializationFailureReason error, string message)
  44. {
  45. Debug.LogError($"详细失败信息: {error} - {message}");
  46. }
  47. public PurchaseProcessingResult ProcessPurchase(PurchaseEventArgs args)
  48. {
  49. if (args.purchasedProduct.definition.id == subscriptionId)
  50. {
  51. Debug.Log("订阅成功!");
  52. // 解锁功能
  53. }
  54. return PurchaseProcessingResult.Complete;
  55. }
  56. public void OnPurchaseFailed(Product product, PurchaseFailureDescription failureDescription)
  57. {
  58. Debug.LogError($"购买失败: {failureDescription.message}");
  59. }
  60. public void OnPurchaseFailed(Product product, PurchaseFailureReason failureReason)
  61. {
  62. Debug.LogError($"购买失败: {failureReason}");
  63. }
  64. public bool IsSubscribed()
  65. {
  66. if (controller == null)
  67. return false;
  68. Product product = controller.products.WithID(subscriptionId);
  69. if (product != null && product.hasReceipt)
  70. {
  71. string receipt = product.receipt;
  72. // 解析 JSON(第一层是 Unity 封装的 JSON)
  73. var receiptDict = (Dictionary<string, object>)UnityEngine.Purchasing.MiniJSON.Json.Deserialize(receipt);
  74. if (receiptDict.TryGetValue("Payload", out object payloadObj))
  75. {
  76. #if UNITY_IOS
  77. // iOS 平台下,Payload 是 Apple 的 base64 收据字符串
  78. string base64Receipt = payloadObj.ToString();
  79. // 解码 base64,得到 Apple 的 JSON 收据(PKCS7 → JSON)
  80. // 没有服务端,这一步只能依赖 Unity IAP 自动提供的结构
  81. var appleReceipt = UnityEngine.Purchasing.MiniJSON.Json.Deserialize(base64Receipt) as Dictionary<string, object>;
  82. if (appleReceipt != null && appleReceipt.TryGetValue("latest_receipt_info", out object latestInfoObj))
  83. {
  84. var latestList = latestInfoObj as List<object>;
  85. if (latestList != null && latestList.Count > 0)
  86. {
  87. var latest = latestList[latestList.Count - 1] as Dictionary<string, object>;
  88. if (latest != null && latest.TryGetValue("expires_date_ms", out object expiresMsObj))
  89. {
  90. long expiresMs = long.Parse(expiresMsObj.ToString());
  91. DateTimeOffset expiresTime = DateTimeOffset.FromUnixTimeMilliseconds(expiresMs);
  92. if (expiresTime > DateTimeOffset.UtcNow)
  93. {
  94. Debug.Log("订阅有效,过期时间:" + expiresTime);
  95. return true;
  96. }
  97. else
  98. {
  99. Debug.Log("订阅已过期:" + expiresTime);
  100. }
  101. }
  102. }
  103. }
  104. #else
  105. Debug.LogWarning("非 iOS 平台,无法解析 iOS 订阅");
  106. #endif
  107. }
  108. }
  109. Debug.Log("未订阅或订阅已过期");
  110. return false;
  111. }
  112. public void BuySubscription()
  113. {
  114. if (controller == null) return;
  115. Product product = controller.products.WithID(subscriptionId);
  116. if (product != null && product.availableToPurchase)
  117. {
  118. controller.InitiatePurchase(product);
  119. }
  120. else
  121. {
  122. Debug.LogWarning("订阅商品未准备好");
  123. }
  124. }
  125. }