Unity无代码IAP购买数据恢复及历史保存问题咨询
关于In-App Purchase购买恢复的问题解答
嘿,我来帮你理清楚这个IAP恢复的问题,先直接给你明确答案,再一步步说怎么实现你要的功能:
先回答你的核心疑问
- 消耗品(金币类):默认情况下,苹果和谷歌的IAP系统都不会自动恢复消耗品的购买记录——因为这类商品设计就是"买一次用一次",系统不会帮你留存这类消费记录。所以玩家删了应用或者换设备重装后,之前买的100金币这类消耗品,现在的代码逻辑下是找不回来的。
- 非消耗品(去广告):非消耗品是支持通过官方IAP接口恢复的,但你当前的代码完全没处理恢复逻辑,所以现在重装后也不会自动恢复,得手动加恢复流程才行。
实现购买历史恢复的具体方案
1. 非消耗品(去广告)的恢复实现
你需要在游戏启动时(比如进入主界面的时机)添加恢复购买的逻辑,调用Unity IAP的RestoreTransactions方法,然后在购买回调里处理去广告的状态。
给你一段示例代码,你可以整合到你的IAP管理类里:
using UnityEngine.Purchasing; public class IAPManager : IStoreListener { private IStoreController m_StoreController; private IExtensionProvider m_ExtensionProvider; // 初始化IAP的代码(你应该已经有类似的了) public void InitializePurchasing() { // ...你的初始化逻辑,获取m_StoreController和m_ExtensionProvider } // 触发恢复购买的方法,可以在游戏启动时调用,或者加个"恢复购买"按钮让玩家手动点 public void RestorePurchases() { if (!m_StoreController.IsInitialized()) { Debug.LogError("IAP还没初始化,没法恢复购买"); return; } // 苹果平台要求必须有明确的恢复入口,谷歌可以自动处理但最好也支持手动恢复 if (Application.platform == RuntimePlatform.IPhonePlayer || Application.platform == RuntimePlatform.OSXPlayer) { Debug.Log("开始恢复已购项目..."); m_StoreController.RestoreTransactions((success) => { if (success) { Debug.Log("恢复成功,已购项目会自动同步"); } else { Debug.Log("恢复失败,可能没有已购项目或者网络有问题"); } }); } else { Debug.Log("安卓平台自动检查已购非消耗品"); CheckExistingNonConsumables(); } } // 处理购买/恢复购买的核心回调 public PurchaseProcessingResult ProcessPurchase(PurchaseEventArgs args) { string productId = args.purchasedProduct.definition.id; string transactionId = args.purchasedProduct.transactionID; switch (productId) { case "removeads": // 把去广告状态存在本地,启动时就检查这个值 PlayerPrefs.SetInt("HasRemovedAds", 1); PlayerPrefs.Save(); // 这里调用你的去广告逻辑,比如隐藏广告组件 ApplyRemoveAds(); break; // 处理金币类消耗品 case "Gold.50": case "Gold.100": case "Gold.250": case "Gold.500": case "Gold.1000": // 关键:用订单ID标记是否已经处理过这个购买,避免重复加金币 if (!PlayerPrefs.HasKey("ProcessedTxn_" + transactionId)) { int addGold = int.Parse(productId.Split('.')[1]); int currentGold = PlayerPrefs.GetInt("Gold", 0); PlayerPrefs.SetInt("Gold", currentGold + addGold); GoldText.text = PlayerPrefs.GetInt("Gold").ToString(); // 标记这个订单已经处理过 PlayerPrefs.SetInt("ProcessedTxn_" + transactionId, 1); PlayerPrefs.Save(); } break; default: Debug.LogWarning("未知的商品ID:" + productId); break; } return PurchaseProcessingResult.Complete; } // 安卓平台主动检查已购非消耗品 private void CheckExistingNonConsumables() { foreach (var product in m_StoreController.products.all) { if (product.definition.type == ProductType.NonConsumable && product.hasReceipt) { if (product.definition.id == "removeads") { PlayerPrefs.SetInt("HasRemovedAds", 1); PlayerPrefs.Save(); ApplyRemoveAds(); } } } } // 封装去广告的逻辑,方便调用 private void ApplyRemoveAds() { // 这里写你的实际去广告代码,比如: // FindObjectOfType<AdBanner>().gameObject.SetActive(false); Debug.Log("已应用去广告"); } // 其他IAP接口实现(比如OnInitializeFailed、OnPurchaseFailed) public void OnInitializeFailed(InitializationFailureReason error) {} public void OnPurchaseFailed(Product product, PurchaseFailureReason failureReason) {} }
2. 消耗品(金币)的跨设备恢复方案
刚才说了,官方IAP不支持消耗品的自动恢复,所以要让玩家换设备/重装后能找回金币,必须用云端存储:
- 可以用Unity官方的Cloud Save,或者Firebase Realtime Database、Firestore这类第三方服务。
- 每次玩家购买消耗品后,把购买记录(订单ID、购买的金币数量、玩家唯一标识)上传到云端。
- 游戏启动时,从云端拉取玩家的所有未重复处理的购买记录,同步金币数量。
如果暂时不想搞云端,用PlayerPrefs存订单ID只能解决同一设备上的重复购买问题,换设备还是会丢失,所以这只是临时方案,长期来看一定要上云端。
3. 对你当前脚本的优化提醒
你现在的代码直接在购买成功后就加金币,没有处理订单重复的问题,也没有恢复逻辑,所以:
- 把所有购买处理逻辑移到
ProcessPurchase回调里,这样恢复购买时也能触发相同的逻辑。 - 必须用订单ID来标记每个消耗品购买是否已经处理,不然恢复时会重复加金币。
- 非消耗品一定要把状态存在本地(比如
PlayerPrefs),游戏启动时先检查这个状态,直接应用去广告。
最后总结一下
- 非消耗品:通过调用
RestoreTransactions就能恢复,只要在代码里监听回调并设置状态就行。 - 消耗品:官方不自动恢复,必须自己做云端存储购买记录,才能跨设备/重装后找回。
- 不管是哪种商品,都要处理订单ID的重复校验,避免玩家重复获得福利。
内容的提问来源于stack exchange,提问作者duhaonur
相关产品推荐
相关产品推荐

