安装插件
方式一:本地 UnityPackage 安装
方式二:通过 Git URL 安装
打开 Package Manager (Window -> Package Manger)
点击左上角 + 图标,选择:Install Package form git URL
输入:https://github.com/AthanaSDK/athana_unity_plugin.git
集成配置
确认 Edit -> Project Settings -> Player -> Settings for Android -> Publishing Settings -> Build 中,勾选:
Custom Launcher Gradle Template
Custom Base Gradle Template
编辑 ${UNITY_PROJEECT}\Assets\Plugins\Android\baseProjectTemplate.gradle
1 2 3 4 5 6 7 8 9 10 11 12 plugins { ... id "org.jetbrains.kotlin.android" version "2.0.21" apply false id "com.google.gms.google-services" version "4.4.2" apply false id "com.google.firebase.crashlytics" version "3.0.4" apply false **BUILD_SCRIPT_DEPS** } ...
编辑 ${UNITY_PROJEECT}\Assets\Plugins\Android\launcherTemplate.gradle
1 2 3 4 5 6 apply plugin: 'com.android.application' apply plugin: 'org.jetbrains.kotlin.android' apply from: 'athana_options.gradle' ...
进入配置面板(Unity Editor -> Assets -> Athana -> Sdk Configuration),填选数据
初始化 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 using Athana;using Athana.Callbacks;using Athana.Api;using static Athana.Api.AthanaInterface;using static Athana.Callbacks.AthanaCallbacks;public class MainSceneController : MonoBehaviour { void Start () { ... InitAthanaSdk() ... AthanaSdk.Start(false ); } private void InitAthanaSdk () { long appId = 00000000000 ; string appKey = "******************" ; string appSecret = "*****************************" ; string appsFlyerDevKey = "******************" ; string maxDevKey = "******************" ; string googleWebClintId = "******************" ; bool testMode = false ; bool debug = false ; var preloadAds = new Dictionary<AdType, string >() { { AdType.AppOpen, "******************" }, { AdType.Rewarded, "******************" }, { AdType.Interstitial, "******************" }, }; AthanaSdk.Initialize(appId, appKey, appSecret, testMode: testMode, debug: debug, serviceConfig: new () { AccountConfig = new () { googleWebClientId = googleWebClintId, }, AdServiceConfigs = new () { max = new () { sdkKey = maxDevKey, debug = debug, preloadAds = AthanaUtils.preloadAds2String(preloadAds) } }, ConversionServiceConfigs = new () { appsflyer = new () { sdkKey = appsFlyerDevKey, } } }); } }
功能调用
对于没有后端、账户体系的游戏,在 SDK 初始化后,需要走 注册平台账户 流程;
对于有账户体系的游戏,在 SDK 初始化后,可参照以下流程:
通过Athana.CurrentUser()查询当前是否有登录账户
如果没有则可:注册游客账户 或 跳转至登录方式选择页面
在通过新手教程后,引导用户绑定三方账号
查询当前账户的三方登录绑定状态:``
注册平台账户 适用于无账户体系的游戏
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 using Athana;using Athana.Callbacks;using Athana.Api;using static Athana.Api.AthanaInterface;using static Athana.Callbacks.AthanaCallbacks;private Action<SdkCallback<AccountInfo?>>? onCurrentUserResult;private Action<SdkCallback<AccountInfo>>? onRegistryUserResult;public void CurrentUser (){ if (onCurrentUserResult == null ) { onCurrentUserResult = (SdkCallback<AthanaInterface.AccountInfo?> result) => { if (result.isSuccess()) { var data = result.data; if (data == null ) { RegistryUser() } else { } } else { Debug.Log("Failed to get current user. error: " + result.error?.msg); } }; AthanaCallbacks.OnCurrentUserResult += onCurrentUserResult; } AthanaSdk.CurrentUser(); } public void RegistryUser (){ if (onRegistryUserResult == null ) { onRegistryUserResult = (SdkCallback<AthanaInterface.AccountInfo> result) => { if (result.isSuccess()) { var data = result.data; Debug.Log("User(" + data.userId + ") register is successed." ); } else { Debug.Log("Failed to register user. error: " + result.error?.msg); } }; AthanaCallbacks.OnRegistryUserResult += onRegistryUserResult; } var extra = new Dictionary<string , object >(); AthanaSdk.RegistryUser(extra: extra); }
三方登录 适用于有账户体系的游戏
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 using Athana;using Athana.Callbacks;using Athana.Api;using static Athana.Api.AthanaInterface;using static Athana.Callbacks.AthanaCallbacks;private Action<SdkCallback<AccountInfo>>? onSignInResult;private Action<SdkCallback<AccountInfo>>? onSignInWithUIResult;public void SignIn (AthanaInterface.SignInType type ){ if (onSignInResult == null ) { onSignInResult = (SdkCallback<AthanaInterface.AccountInfo> result) => { if (result.isSuccess()) { var data = result.data; Debug.Log("User(" + data.userId + ") Sign-In is successed." ); } else { Debug.Log("SignIn is failure. error: " + result.error?.msg); } }; AthanaCallbacks.OnSignInResult += onSignInResult; } AthanaSdk.SignIn(signInType: type); } public void SignInWithUI (){ if (onSignInWithUIResult == null ) { onSignInWithUIResult = (SdkCallback<AthanaInterface.AccountInfo> result) => { if (result.isSuccess()) { var data = result.data; Debug.Log("User(" + data.userId + ") Sign-In is successed." ); } else { Debug.Log("SignIn is failure. error: " + result.error?.msg); } }; AthanaCallbacks.OnSignInWithUIResult += onSignInWithUIResult; } AthanaSdk.SignInWithUI(); }
三方账号绑定 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 using Athana;using Athana.Callbacks;using Athana.Api;using static Athana.Api.AthanaInterface;using static Athana.Callbacks.AthanaCallbacks;private Action<SdkCallback<object ?>>? onAccountBindingResult;private Action<SdkCallback<object ?>>? onAccountUnbindResult;private Action<SdkCallback<TriAccountBindMap>>? onQueryAllAccountBindResult;public void AccountBinding (SignInType signType ){ if (onAccountBindingResult == null ) { onAccountBindingResult = (SdkCallback<object ?> result) => { if (result.isSuccess()) { Debug.Log("Account Binding is successed." ); } else { Debug.Log("Account Binding is failure." ); Debug.Log("Account Binding is failure. error: " + result.error?.msg); } }; AthanaCallbacks.OnAccountBindingResult += onAccountBindingResult; } AthanaSdk.AccountBinding(signInType: signType); }
三方账号解绑 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 using Athana;using Athana.Callbacks;using Athana.Api;using static Athana.Api.AthanaInterface;using static Athana.Callbacks.AthanaCallbacks;private Action<SdkCallback<object ?>>? onAccountUnbindResult;public void AccountUnbind (SignInType signType, TriAccount tri ){ if (onAccountUnbindResult == null ) { onAccountUnbindResult = (SdkCallback<object ?> result) => { if (result.isSuccess()) { Debug.Log("Account Unbind is successed." ); } else { Debug.Log("Account Unbind is failure. error: " + result.error?.msg); } }; AthanaCallbacks.OnAccountUnbindResult += onAccountUnbindResult; } AthanaSdk.AccountUnbind(signType, OpenId); }
查询三方绑定状态 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 using Athana;using Athana.Callbacks;using Athana.Api;using static Athana.Api.AthanaInterface;using static Athana.Callbacks.AthanaCallbacks;private Action<SdkCallback<TriAccountBindMap>>? onQueryAllAccountBindResult;private TriAccountBindMap? BindResults;public void QueryAllAccountBind (){ if (onQueryAllAccountBindResult == null ) { onQueryAllAccountBindResult = (SdkCallback<TriAccountBindMap> result) => { if (result.isSuccess()) { BindResults = result.data; Debug.Log("Query Account Bind is successed." ); } else { Debug.Log("Query Account Bind is failure. error: " + result.error?.msg); } }; AthanaCallbacks.OnQueryAllAccountBindResult += onQueryAllAccountBindResult; } AthanaSdk.QueryAllAccountBind(); }
广告 AppLovin MAX 的广告源适配器依赖需要手动添加,详见文档:
启动广告 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 using Athana;using Athana.Callbacks;using Athana.Api;using static Athana.Api.AthanaInterface;using static Athana.Callbacks.AthanaCallbacks;private Action<ProxyAd>? onAdLoadedEvent = null ;private Action<ProxyAd, AdError>? onLoadFailedEvent = null ;public void LoadAppOpenAd (){ if (onAdLoadedEvent == null ) { onAdLoadedEvent = (ad) => { Debug.Log("Load AppOpen Ad is successed." ); }; AppOpenAd.OnLoadedEvent += onAdLoadedEvent; } if (onLoadFailedEvent == null ) { onLoadFailedEvent = (ad, error) => { Debug.Log("Load AppOpen Ad is failure." ); }; AppOpenAd.OnLoadFailedEvent += onLoadFailedEvent; } AthanaSdk.LoadAppOpenAd(AppOpenAdUnitId); } public void ShowAppOpenAd (){ if (AthanaSdk.IsReadyAppOpenAd(AppOpenAdUnitId)) { AthanaSdk.ShowAppOpenAd(AppOpenAdUnitId, placement: "AppOpenAd" ); } else { LoadAppOpenAd(); } }
插屏广告 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 using Athana;using Athana.Callbacks;using Athana.Api;using static Athana.Api.AthanaInterface;using static Athana.Callbacks.AthanaCallbacks;private Action<ProxyAd>? onAdLoadedEvent = null ;private Action<ProxyAd, AdError>? onLoadFailedEvent = null ;public void LoadInterstitialAd (){ if (onAdLoadedEvent == null ) { onAdLoadedEvent = (ad) => { Debug.Log("Load Interstitial Ad is successed." ); }; AppOpenAd.OnLoadedEvent += onAdLoadedEvent; } if (onLoadFailedEvent == null ) { onLoadFailedEvent = (ad, error) => { Debug.Log("Load Interstitial Ad is failure." ); }; AppOpenAd.OnLoadFailedEvent += onLoadFailedEvent; } AthanaSdk.LoadInterstitialAd(InterstitialAdUnitId); } public void ShowInterstitialAd (){ if (AthanaSdk.IsReadyInterstitialAd(InterstitialAdUnitId)) { AthanaSdk.ShowInterstitialAd(InterstitialAdUnitId, placement: "InterstitialAd" ); } else { LoadInterstitialAd(); } }
激励广告 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 using Athana;using Athana.Callbacks;using Athana.Api;using static Athana.Api.AthanaInterface;using static Athana.Callbacks.AthanaCallbacks;private Action<ProxyAd>? onAdLoadedEvent = null ;private Action<ProxyAd, AdError>? onLoadFailedEvent = null ;private Action<ProxyAd>? onRewardedEvent = null ;public void LoadRewardedAd (){ if (onAdLoadedEvent == null ) { onAdLoadedEvent = (ad) => { Debug.Log("Load Rewarded Ad is successed." ); }; AppOpenAd.OnLoadedEvent += onAdLoadedEvent; } if (onLoadFailedEvent == null ) { onLoadFailedEvent = (ad, error) => { Debug.Log("Load Rewarded Ad is failure." ); }; AppOpenAd.OnLoadFailedEvent += onLoadFailedEvent; } if (onRewardedEvent == null ) { onRewardedEvent = (ad) => { Debug.Log("Reward received." ); }; RewardedAd.OnRewardedEvent += onRewardedEvent; } AthanaSdk.LoadRewardedAd(RewardedAdUnitId); } public void ShowRewardedAd (){ if (AthanaSdk.IsReadyRewardedAd(RewardedAdUnitId)) { AthanaSdk.ShowRewardedAd(RewardedAdUnitId, placement: "RewardedAd" ); } else { LoadRewardedAd(); } }
横幅广告 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 using Athana;using Athana.Api;private BannerAd? _BannerAd = null ;public void CreateBanner (){ _BannerAd?.Destroy(); _BannerAd = AthanaSdk.CreateBanner(BannerAdUnitId, AdSize.fullWidth(60 ), "Banner" , AdAlignment.TOP_CENTER); } public void HideBanner (){ _BannerAd?.Hide(); } public void ShowBanner (){ _BannerAd?.Show(); }
支付 查询商店服务是否可用 请在调用 QueryProducts、Purchase、QueryPurchaseHistory 方法前调用一次 StoreIsAvailable 方法
可以在调用 StoreIsAvailable 之后,异步延时 400ms 后调用 QueryProducts 或 QueryPurchaseHistory
1 2 3 bool check = AthanaSdk.StoreIsAvailable();
查询商品详情 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 using Athana;using Athana.Callbacks;using Athana.Api;using static Athana.Api.AthanaInterface;using static Athana.Callbacks.AthanaCallbacks;private List<IapProduct> products = new List<IapProduct>();public void QueryProducts (){ if (onQueryProductsResult == null ) { onQueryProductsResult = (SdkCallback<List<IapProduct>> result) => { if (result.isSuccess()) { var data = result.data; if (data == null || data.Count == 0 ) { } else { products.AddRange(data); foreach (var product in data) { } } } else { Debug.Log("Failed to query products. error: " + result.error?.msg); } }; AthanaCallbacks.OnQueryProductsResult += onQueryProductsResult; } var keys = new HashSet<string >(); keys.Add("*********" ); ... AthanaSdk.QueryProducts(keys); }
购买 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public void Purchase (IapProduct product ){ if (onPurchaseResult == null ) { onPurchaseResult = (SdkCallback<object ?> result) => { if (result.isSuccess()) { } else { Debug.Log("Failed to Purchase. error: " + result.error?.msg); } }; AthanaCallbacks.OnPurchaseResult += onPurchaseResult; } AthanaSdk.Purchase(product); }
查询购买历史 PS:不包含一次性消耗类商品,只能提供:在有效期内的订阅订单、非一次性消耗类商品
此方法适用于以下场景:
掉单处理,在应用每次启动都主动查询一次
对内购商品做使用权验证,例如:永久去广告
对订阅商品做有效期验证,例如:月度会员
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 public void QueryPurchaseHistory (){ if (onQueryPurchaseHistoryResult == null ) { onQueryPurchaseHistoryResult = (SdkCallback<List<IapPurchase>> result) => { if (result.isSuccess()) { var data = result.data; foreach (var purchase in data) { if (purchase.isAcknowledged != true ) { var consumable = true ; AthanaSdk.VerifyOrder(purchase, consumable); } Debug.Log("Purchase: " + purchase.purchaseId + ", Product: " + purchase.productId + ", finished: " + purchase.isAcknowledged); } } else { Debug.Log("Failed to query PurchaseHistory. error: " + result.error?.msg); } }; AthanaCallbacks.OnQueryPurchaseHistoryResult += onQueryPurchaseHistoryResult; } AthanaSdk.QueryPurchaseHistory(); }
事件 内置事件 参考:事件服务
发送自定义事件 1 2 3 4 5 6 7 8 var eventKey = "CustomKey" ;var paramMap = new Dictionary<string , object >();paramMap["key1" ] = value1; paramMap["keey2" ] = value2; AthanaSdk.SendEvent(eventKey, paramMap: paramMap);
应用内评分 1 2 AthanaSdk.RequestReview();