[Unity]项目从Google移植到AmazonAppStore

全文 11160 字数 455 行数;
目的将Unity应用 App上架到AmazonAppStore,接入亚马逊的广告,切换到亚马逊内购,本来是上架到Google的;
文章中接入广告的部分适用于Max聚合和Ironsource聚合;

一.更换包名

通常包括:
1.
在这里插入图片描述
2.MainActivity.java
3.MyApplication.java
4.AndroidManifest.xml
5.google-services相关

二.Amazon包不需要firebase(需求)

去掉FIRE_BASE宏,要么删除Firebase
删除google-services
如果还需要 就替换google-services文件

在这里插入图片描述

三.Amazon包af中的channel=Amazon 区分大小写(需求)

AndroidManifest中加入

<meta-data android:name="CHANNEL" android:value="Amazon" />

四.Amazon包数数ID不变通过用户属性拆分2个平台, 新增version,参数Google & Amazon,对应包走对应用户属性(需求)

数数上报

 AnalyticDataHelper.SetUserProperty(UserProperty.version,"Amazon");

五.Amazon包暂时关闭评分功能(需求)

自行关闭

六.Amazon包的内购(主要)

1.先切换到Amazon平台
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

3.下载测试Json用在线json解析看
Json在线解析及格式化验证
在这里插入图片描述

如果有多个订阅VIP,几个subscriptionParent不能一样,因为订阅成功会返回这个值,并且把原来IAPManager中的购买成功回调ProcessPurchase如果有ID校验从原来的

  foreach (IAPProduct product in m_ActiveProducts)
        {
    
    
            if (product.productId == e.purchasedProduct.definition.id)
            {
    
    
                result = product.ProcessPurchase(e);

                if (result == PurchaseProcessingResult.Complete)
                {
    
    

                    consumePurchase = true;
                }

                resultProcessed = true;
            }
        }

改成

  for (int i = 0; i < m_ActiveProducts.Count; i++)
        {
    
    
  if (m_ActiveProducts[i].productId == e.purchasedProduct.definition.id||
                (e.purchasedProduct.definition.id=="weekly"&&m_ActiveProducts[i].productId=="7Days_VIP")||
                (e.purchasedProduct.definition.id=="monthly"&&m_ActiveProducts[i].productId=="30Days_VIP")||
                (e.purchasedProduct.definition.id=="yearly"&&m_ActiveProducts[i].productId=="360Days_VIP"))
            {
    
    
                result = m_ActiveProducts[i].ProcessPurchase(e);

                if (result == PurchaseProcessingResult.Complete)
                {
    
    

                    consumePurchase = true;
                } 

                resultProcessed = true;
            }
        }

SubscriptionChecker里的CheckID换成sub的id
很难受
订单返回的ID不是productId,而是json中的subscriptionParent

如果有类似

IAPManager.Instance.GetSubscriptionInfo(productID)

传入的ID要从之前的productId(例:30Days_VIP)
换成son中的subscriptionParent(例:monthly)

就是说30Days_VIP只用在CataLog,iap按钮上,成功回调校验里 monthly用在获取订阅信息,和成功的主要校验,甚至上报;

在这里插入图片描述
在这里插入图片描述

就是Services-IAP-Catalog里的商品ID和数量要<=导出商品json文件amazon.sdktester.json中的数量;
1.如果付款界面弹不出来,就是Json文件和catalog不对应;
2.如果付款成功之后UI没有表现,就是result = m_ActiveProducts[i].ProcessPurchase(e)上面的判断没走通,id没对应;
3.如果付款完一切正常,再次购买别的商品,出现上一个订单没完成的弹窗,就是成功回调里的
return (consumePurchase) ? PurchaseProcessingResult.Complete : PurchaseProcessingResult.Pending;没走到;

七.Amazon包的广告接入(主要)

1.使用admob的开屏(因为不支持max开屏)

2.更换max或者Ironsource广告相关,开屏广告相关一系列ID和key

3.额外处理APS

下载资源
在这里插入图片描述

[下载aps文件]

导入unity_aps\unity_aps下面的 APS_Core_1_7_0.unitypackage
点击安装max支持如果是Ironsource就安装对应的
在这里插入图片描述
向Android清单添加权限/活动
清单文件中必须存在以下权限:

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />

如果您希望传递地理位置信息,请在您的清单文件中包含以下权限:

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

(必要)在下添加以下内容清单文件的部分:

<activity android:name="com.amazon.device.ads.DTBInterstitialActivity"/>
<activity android:name="com.amazon.device.ads.DTBAdActivity"/>

然后开始把aps广告与之前的max广告混合(Ironsource逻辑一样下面代码以max为例)

Max接入文档
Ironsource接入文档

这个是APPLovin出的接入APS的文档可以参考

新增Amazon广告ID(换成自己广告位的ID)

    //amazon
    public const string AmazonBannerSlotId = "edb16a-007e-40af-a3b5-742e840e4eab";
    public const string AmazonBannerPadSlotId = "680e96-945f-465e-b760-983df01408b23";
    public const string AmazonInterstitialVideoSlotId = "50f2ff-2ea1-46ec-80b4-062c3d067ca1";
    public const string AmazonRewardVideoSlotId = "1c69e0-e71b-475f-904b-d073e6d18213";
    public const string AmazonAppId = "85a752-9410-4fb1-aab2-8dd2332c9d8a";

Amazon广告初始化

#if !UNITY_EDITOR
			Amazon.Initialize(AdMaxType.AmazonAppId);
			Amazon.SetAdNetworkInfo(new AdNetworkInfo(DTBAdNetwork.MAX));
#endif

加载Amazon的APS广告(只需要改加载逻辑)

下面因项目聚合而异(以max为例)
加载Banner
之前的

MaxSdk.LoadRewardedAd(adUnit);

把之前的加载banner部分换成

		private void LoadBanner()
		{
    
    
#if UNITY_EDITOR
			AdsManager.instance.CreateBanner(AdMaxType.BannerId, MaxSdkBase.BannerPosition.BottomCenter);
			return;
#endif
			int width;
			int height;
			string slotId;
			if (MaxSdkUtils.IsTablet())
			{
    
    
				width = 728;
				height = 90;
				slotId = AdMaxType.AmazonBannerPadSlotId;
			}
			else
			{
    
    
				width = 320;
				height = 50;
				slotId = AdMaxType.AmazonBannerSlotId;
			}

			var apsBanner = new APSBannerAdRequest(width, height, slotId);
			apsBanner.onSuccess += (adResponse) =>
			{
    
       
				MaxSdk.SetBannerLocalExtraParameter(AdMaxType.BannerId, "amazon_ad_response", adResponse.GetResponse());
				AdsManager.instance.CreateBanner(AdMaxType.BannerId, MaxSdkBase.BannerPosition.BottomCenter);
				MaxSdk.SetBannerExtraParameter(AdMaxType.BannerId,"allow_pause_auto_refresh_immediately", "true"); 
				AdsManager.instance.HideBanner();
			};
	    
			apsBanner.onFailedWithError += (adError) =>
			{
    
    
				MaxSdk.SetBannerLocalExtraParameter(AdMaxType.BannerId, "amazon_ad_error", adError.GetAdError());
				AdsManager.instance.CreateBanner(AdMaxType.BannerId, MaxSdkBase.BannerPosition.BottomCenter);
				MaxSdk.SetBannerExtraParameter(AdMaxType.BannerId,"allow_pause_auto_refresh_immediately", "true"); 
				AdsManager.instance.HideBanner();
			};

			apsBanner.LoadAd();
		}

如果是Ironsource聚合,banner宽高只能是320*50

特别注意事项(上面代码已经写了):亚马逊banner之前在安卓接入时遇到非预期场景仍展示banner,无法隐藏掉的情况,请开发同学此次接入的时候关注该问题是否还会复现,如果是的话,采用下方hide方式:MaxSdk.SetBannerExtraParameter(“替换实际banner unit id”,“allow_pause_auto_refresh_immediately”, “true”);

加载rewardedVideoAd
之前的

 MaxSdk.LoadRewardedAd(adUnit);
 

把之前的加载激励广告部分换成

 private bool m_isFirstLoadRewardAd = true;
	public override void cacheAdVideo()
	{
    
    
#if UNITY_EDITOR
        string adUnit = AdMaxType.Reward_Android.ToString();//!avVideoRevive ? AdMaxType.Reward_Android.ToString() : AdMaxType.Reward_Android_revive.ToString();
        GameLog.Debug("[AdManager] AppLovin SDK is cacheAdVideo" + adUnit);
        MaxSdk.LoadRewardedAd(adUnit);
        return;
#endif
        if (m_isFirstLoadRewardAd)
        {
    
    
            m_isFirstLoadRewardAd = false;

            var rewardedVideoAd = new APSVideoAdRequest(320, 480, AdMaxType.AmazonRewardVideoSlotId);
            rewardedVideoAd.onSuccess += (adResponse) =>
            {
    
    
                string adUnit = AdMaxType.Reward_Android.ToString();
				
                MaxSdk.SetRewardedAdLocalExtraParameter(adUnit, "amazon_ad_response", adResponse.GetResponse());
                Debug.Log("[AdManager] AppLovin SDK is cacheAdVideo" + adUnit);
                MaxSdk.LoadRewardedAd(adUnit);
            };
            rewardedVideoAd.onFailedWithError += (adError) =>
            {
    
    
                string adUnit = AdMaxType.Reward_Android.ToString();
                MaxSdk.SetRewardedAdLocalExtraParameter(adUnit, "amazon_ad_error", adError.GetAdError());
                Debug.Log("[AdManager] AppLovin SDK is cacheAdVideo" + adUnit);
                MaxSdk.LoadRewardedAd(adUnit);
            };

            rewardedVideoAd.LoadAd();
			
        }
        else
        {
    
    
            string adUnit2 = AdMaxType.Reward_Android.ToString();//!avVideoRevive ? AdMaxType.Reward_Android.ToString() : AdMaxType.Reward_Android_revive.ToString();
            GameLog.Debug("[AdManager] AppLovin SDK is cacheAdVideo" + adUnit2);
            MaxSdk.LoadRewardedAd(adUnit2);
        }
        

    }

加载interstitialVideoAd
之前的

	string adUnit = AdMaxType.Interstitial_android.ToString();
		string adUnit2 = AdMaxType.Interstitial_android2.ToString();
#if UNITY_EDITOR
	
		if (!isInterstitialVideoAvailableStr(adUnit))
		{
    
    
			Debug.Log("[AdManager] AppLovin SDK is cacheInterstitialVideo" + adUnit);
			MaxSdk.LoadInterstitial(adUnit);
			AnalyticDataHelper.Track("adi_request_load", new Dictionary<string, object>()
			{
    
    
			});
		}

		if (!isInterstitialVideoAvailableStr(adUnit2))
		{
    
    
			Debug.Log("[AdManager] AppLovin SDK is cacheInterstitialVideo" + adUnit2);

			MaxSdk.LoadInterstitial(adUnit2);

			AnalyticDataHelper.Track("adi_request_load", new Dictionary<string, object>()
			{
    
    
			});
		}

		Debug.Log("[AdsManager] adi_request_load ");
		return;
#endif

改成

    private bool m_isFirstLoadIntersAd = true;
    public override void cacheInterstitialVideo()
	{
    
    
		string adUnit = AdMaxType.Interstitial_android.ToString();
		string adUnit2 = AdMaxType.Interstitial_android2.ToString();
#if UNITY_EDITOR
	
		if (!isInterstitialVideoAvailableStr(adUnit))
		{
    
    
			Debug.Log("[AdManager] AppLovin SDK is cacheInterstitialVideo" + adUnit);
			MaxSdk.LoadInterstitial(adUnit);
			AnalyticDataHelper.Track("adi_request_load", new Dictionary<string, object>()
			{
    
    
			});
		}

		if (!isInterstitialVideoAvailableStr(adUnit2))
		{
    
    
			Debug.Log("[AdManager] AppLovin SDK is cacheInterstitialVideo" + adUnit2);

			MaxSdk.LoadInterstitial(adUnit2);

			AnalyticDataHelper.Track("adi_request_load", new Dictionary<string, object>()
			{
    
    
			});
		}

		Debug.Log("[AdsManager] adi_request_load ");
		return;
#endif
		if (m_isFirstLoadIntersAd)
		{
    
    
			m_isFirstLoadIntersAd = false;

			var interstitialVideoAd = new APSVideoAdRequest(320, 480, AdMaxType.AmazonInterstitialVideoSlotId);
			interstitialVideoAd.onSuccess += (adResponse) =>
			{
    
    
				Debug.Log("interstitialVideoAd.onSuccess");
				MaxSdk.SetInterstitialLocalExtraParameter(AdMaxType.Interstitial_android, "amazon_ad_response", adResponse.GetResponse());
				MaxSdk.SetInterstitialLocalExtraParameter(AdMaxType.Interstitial_android2, "amazon_ad_response", adResponse.GetResponse());
				MaxSdk.LoadInterstitial(adUnit);
				MaxSdk.LoadInterstitial(adUnit2);
			};
			interstitialVideoAd.onFailedWithError += (adError) =>
			{
    
    
				Debug.Log("interstitialVideoAd.onFailedWithError");
				MaxSdk.SetInterstitialLocalExtraParameter(AdMaxType.Interstitial_android, "amazon_ad_error", adError.GetAdError());
				MaxSdk.SetInterstitialLocalExtraParameter(AdMaxType.Interstitial_android2, "amazon_ad_error", adError.GetAdError());
				MaxSdk.LoadInterstitial(adUnit);
				MaxSdk.LoadInterstitial(adUnit2);
			};

			interstitialVideoAd.LoadAd();
		}
		else
		{
    
    
			if (!isInterstitialVideoAvailableStr(adUnit))
			{
    
    
				Debug.Log("[AdManager] AppLovin SDK is cacheInterstitialVideo" + adUnit);
				MaxSdk.LoadInterstitial(adUnit);
				AnalyticDataHelper.Track("adi_request_load", new Dictionary<string, object>()
				{
    
    
				});
			}

			if (!isInterstitialVideoAvailableStr(adUnit2))
			{
    
    
				Debug.Log("[AdManager] AppLovin SDK is cacheInterstitialVideo" + adUnit2);

				MaxSdk.LoadInterstitial(adUnit2);

				AnalyticDataHelper.Track("adi_request_load", new Dictionary<string, object>()
				{
    
    
				});
			}

			Debug.Log("[AdsManager] adi_request_load ");
		}
		
    }

APS接入End;

4.测试APS广告

要启用SDK日志记录和测试模式,请调用以下方法。

// Enable testing and logging.
Amazon.EnableTesting (true); // Make sure to take this off when going live.
Amazon.EnableLogging (true);

查看错误代码集成验证

日志过滤errorCode
1.ErrorCode–400
Response :{“instrPixelURL”:“https://aax-us-east.amazon-adsystem.com/x/px/p/null/”,“errorMessage”:“[INVALID_REQUEST]”,“errorCode”:“400”,“status”:“error”}
后台广告尺寸配置问题,注意banner 有pad和普通两个尺寸

八.Amazon包广告需求ID更换

1.更换Max(Ironsource)相关的ID
2.更换AndroidManifest中的AppID
3.更换Amazon 广告ID
4.更换开屏相关的ID(包括Assets-GoogleMobileAds-Settings选项下的appid)

注:开屏 admob 正式ID,在未上架之前不填广告,技术代码则需要替换测试ID,然后打包给测试,测试好没问题之后,上线之前技术代码侧再换成正式ID

猜你喜欢

转载自blog.csdn.net/qq_42980269/article/details/133988850