很多项目都会遇到内购和订阅相关模块,这里我总结一下内购接入的时候遇到的各种坑,以及内购测试的时候,有什么比较好的方法测试。本篇先介绍Android篇。
打开Unity编辑器,找到Servic,启用IAP 服务。(启动后也会默认打开数据分析服务)
imageIAP设置页面,需要设置app适用年龄,根据自己产品自行选择年龄是否13+,然后需要去注意有个Options选项,需要填入一个Google Public Key,这个Key在Google后台,关联产品后就有了,会自动填写上。
image接下来就是IAP文档的内容了,建议去官网看文档,这里我把基本框架写出来。
参考:https://docs.unity3d.com/cn/current/Manual/UnityIAP.html
首先创建一个IAPManager
public class IAPManager : MonoBehaviour,IStoreListener
{
private static IAPManager _instance;
public static IAPManager Instance
{
get
{
if (!_instance)
{
_instance = FindObjectOfType(typeof(IAPManager)) as IAPManager;
}
return _instance;
}
}
}
初始化IAP,并且创建好所有内购产品(提前在后台生成ProduceID)
private void InitializePurchasing()
{
Debug.Log("IAP InitializePurchasing...1");
if (IsInitialized())
{
return;
}
Debug.Log("IAP InitializePurchasing...2");
iapItems = new[]
{
new IAPItem(IAPConstants.IdDiamond1, ProductType.Consumable),
new IAPItem(IAPConstants.IdDiamond2, ProductType.NonConsumable),
new IAPItem(IAPConstants.IdDiamond3, ProductType.Subscription)
};
//在除 Google Play 商店以外的其他 Android 应用商店中发布游戏
//加条件 SelectedAndoidAppStore == AppStore.GooglePlay
//Application.platform == RuntimePlatform.Android ? Google.Play.Billing.GooglePlayStoreModule.Instance() :
ConfigurationBuilder builder;
if (Application.platform == RuntimePlatform.Android)
{
builder = ConfigurationBuilder.Instance(Google.Play.Billing.GooglePlayStoreModule.Instance());
}
else
{
builder = ConfigurationBuilder.Instance(StandardPurchasingModule.Instance());
}
//var builder = ConfigurationBuilder.Instance(StandardPurchasingModule.Instance());
foreach (var item in iapItems)
{
builder.AddProduct(item.productID, item.productType, new IDs {
{item.productID, GooglePlay.Name}
}
);
}
isInitialingPruchasing = true;
UnityPurchasing.Initialize (this, builder);
Debug.Log("IAP InitializePurchasing...3");
}
创建IAPItem时候,传入产品ID和产品类型要与后台一致。
初始化成功:
/// <summary>
/// Unity IAP 准备好可以进行购买时调用。
/// </summary>
public void OnInitialized (IStoreController controller, IExtensionProvider extensions)
{
Debug.Log("IAP OnInitialized: PASS");
m_StoreController = controller;
m_StoreExtensionProvider = extensions;
m_AppleExtensions = extensions.GetExtension<IAppleExtensions>();
checkSubscriptionInfo();
if (OnInitialSuccessAction != null) {
OnInitialSuccessAction();
}
isInitialingPruchasing = false;
}
初始化失败:
/// <summary>
/// Unity IAP 遇到不可恢复的初始化错误时调用。
/// 请注意,如果互联网不可用,则不会调用此项;Unity IAP将尝试初始化,直到互联网变为可用。
/// </summary>
/// <param name="error"></param>
public void OnInitializeFailed (InitializationFailureReason error)
{
isInitialingPruchasing = false;
if(OnInitialFailAction != null) {
OnInitialFailAction();
}
Debug.Log("IAP OnInitializeFailed reason = " + error.ToString());
switch (error)
{
case InitializationFailureReason.AppNotKnown:
Debug.Log("IAP Is your App correctly uploaded on the relevant publisher console?");
break;
case InitializationFailureReason.PurchasingUnavailable:
Debug.Log("IAP Billing disabled!");
break;
case InitializationFailureReason.NoProductsAvailable:
Debug.Log("IAP No products available for purchase!");
break;
default:
throw new ArgumentOutOfRangeException(nameof(error), error, null);
}
}
购买产品,传入对应产品ID:
void BuyProductID(string productId)
{
if (IsInitialized())
{
Product product = m_StoreController.products.WithID(productId);
if (product != null && product.availableToPurchase)
{
Debug.Log(string.Format("IAP Purchasing product asychronously: '{0}'", product.definition.id));
m_StoreController.InitiatePurchase(product);
}
else
{
Debug.Log("IAP BuyProductID: FAIL. Not purchasing product, either is not found or is not available for purchase");
}
}
else
{
if(isInitialingPruchasing) {
//正在初始化,则等待初始化成功后继续购买
} else {
if (OnPurchaseFailedAction != null)
OnPurchaseFailedAction();
InitializePurchasing();
}
Debug.Log("IAP BuyProductID FAIL. Not initialized.");
}
}
购买成功:
/// <summary>
/// 购买完成时调用。
/// 可能在 OnInit ialized() 之后的任何时间调用。
/// </summary>
public PurchaseProcessingResult ProcessPurchase (PurchaseEventArgs args)
{
Debug.Log("IAP ProcessPurchase");
IAPItem item = null;
foreach(var i in iapItems)
{
Debug.Log("IAP ProcessPurchase productID : " + args.purchasedProduct.definition.id + ", i = "+ i + " : " + i.productID);
if (!string.Equals(args.purchasedProduct.definition.id, i.productID, StringComparison.Ordinal))
continue;
Debug.Log(string.Format("ProcessPurchase: PASS. Product: '{0}'", args.purchasedProduct.definition.id));
item = i;
}
onItemPurchased?.Invoke(item);
return PurchaseProcessingResult.Complete;
}
购买失败:
/// <summary>
/// 购买失败时调用。
/// </summary>
public void OnPurchaseFailed (Product product, PurchaseFailureReason failureReason)
{
// A product purchase attempt did not succeed. Check failureReason for more detail. Consider sharing
// this reason with the user to guide their troubleshooting actions.
Debug.Log(string.Format("OnPurchaseFailed: FAIL. Product: '{0}', PurchaseFailureReason: {1}", product.definition.storeSpecificId, failureReason));
}
这几个方法,一定打好log,这里就是核心的几个内购方法,另外当接入google结算库时候,要引入Google.Play.Billing时候,编辑器可能报错找不到。
在Player Settings -> Other Settings 添加宏定义:
image.png
网友评论