Compare commits
35 Commits
c0c557b34e
...
5c1f73fc18
| Author | SHA1 | Date |
|---|---|---|
|
|
5c1f73fc18 | |
|
|
8a81ed78b4 | |
|
|
76fc4f5c26 | |
|
|
72bf076537 | |
|
|
19a46fff1e | |
|
|
4989926a47 | |
|
|
fe691235d6 | |
|
|
dc47cec8bd | |
|
|
2075f676b9 | |
|
|
660303e45d | |
|
|
2a895b370e | |
|
|
1256880b22 | |
|
|
8cc083410d | |
|
|
81f37625c1 | |
|
|
1a9481b094 | |
|
|
2174bcf1a3 | |
|
|
602662881c | |
|
|
e36f7483a3 | |
|
|
7cbc5ac148 | |
|
|
e8b3112cc5 | |
|
|
e0e78da9a3 | |
|
|
9e7e94ef36 | |
|
|
80e38bf85d | |
|
|
cfe81b5583 | |
|
|
34ae9e3f0b | |
|
|
eba48e4a75 | |
|
|
a53c153338 | |
|
|
ffcb846a64 | |
|
|
dbb56e5a32 | |
|
|
b6e038a027 | |
|
|
4e24169b25 | |
|
|
9024b8171c | |
|
|
f96e506a19 | |
|
|
c59f76aead | |
|
|
ba90a32195 |
|
|
@ -1,8 +1,8 @@
|
||||||
{
|
{
|
||||||
"name": "Guru.Editor",
|
"name": "Guru.Editor",
|
||||||
"rootNamespace": "",
|
|
||||||
"references": [
|
"references": [
|
||||||
"Guru.Runtime"
|
"Guru.Runtime",
|
||||||
|
"Guru.Notification"
|
||||||
],
|
],
|
||||||
"includePlatforms": [
|
"includePlatforms": [
|
||||||
"Editor"
|
"Editor"
|
||||||
|
|
|
||||||
|
|
@ -41,8 +41,8 @@ namespace Guru.Editor
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Firebase 10.20.0 fixed to 10.22.0. BUT higher version do not open this ATTRIBUTE !!
|
||||||
[PostProcessBuild(47)] // MAX POD Process Order
|
// [PostProcessBuild(47)] // MAX POD Process Order
|
||||||
public static void PostBuildFixPodDeps(BuildTarget target, string projPath)
|
public static void PostBuildFixPodDeps(BuildTarget target, string projPath)
|
||||||
{
|
{
|
||||||
if (target != BuildTarget.iOS) return;
|
if (target != BuildTarget.iOS) return;
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ namespace Guru
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class IOSPostBuildSwift
|
public class IOSPostBuildSwift
|
||||||
{
|
{
|
||||||
[PostProcessBuild(40)]
|
[PostProcessBuild(2000)]
|
||||||
public static void OnPostProcessBuild(BuildTarget target, string buildPath)
|
public static void OnPostProcessBuild(BuildTarget target, string buildPath)
|
||||||
{
|
{
|
||||||
if (target != BuildTarget.iOS) return;
|
if (target != BuildTarget.iOS) return;
|
||||||
|
|
@ -43,7 +43,7 @@ namespace Guru
|
||||||
|
|
||||||
// 设置主项目的SWIFT构建支持
|
// 设置主项目的SWIFT构建支持
|
||||||
project.SetBuildProperty(mainTargetGuid, "ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES", "YES");
|
project.SetBuildProperty(mainTargetGuid, "ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES", "YES");
|
||||||
|
project.SetBuildProperty(frameworkTargetGuid, "ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES", "NO");
|
||||||
|
|
||||||
project.WriteToFile(projectPath);
|
project.WriteToFile(projectPath);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@
|
||||||
"MaxSdk",
|
"MaxSdk",
|
||||||
"MaxSdk.Scripts",
|
"MaxSdk.Scripts",
|
||||||
"Amazon",
|
"Amazon",
|
||||||
|
"Amazon.Scripts",
|
||||||
"OpenWrapSDK",
|
"OpenWrapSDK",
|
||||||
"UniWebView-CSharp",
|
"UniWebView-CSharp",
|
||||||
"UnityEngine.Purchasing",
|
"UnityEngine.Purchasing",
|
||||||
|
|
@ -17,7 +18,9 @@
|
||||||
"Google.Play.Review",
|
"Google.Play.Review",
|
||||||
"Google.Play.Common",
|
"Google.Play.Common",
|
||||||
"Guru.LitJson",
|
"Guru.LitJson",
|
||||||
"Unity.Advertisement.IosSupport"
|
"Unity.Advertisement.IosSupport",
|
||||||
|
"Unity.Notifications.Android",
|
||||||
|
"Unity.Notifications.iOS"
|
||||||
],
|
],
|
||||||
"includePlatforms": [],
|
"includePlatforms": [],
|
||||||
"excludePlatforms": [],
|
"excludePlatforms": [],
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,14 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
namespace Guru
|
namespace Guru
|
||||||
{
|
{
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using com.adjust.sdk;
|
using com.adjust.sdk;
|
||||||
|
using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
|
|
||||||
public static class AdjustService
|
public class AdjustService
|
||||||
{
|
{
|
||||||
public const string Version = "1.6.1";
|
public const string Version = "1.6.1";
|
||||||
public const string AdjustVersion = "4.38.0"; // Adjust SDK Version
|
public const string AdjustVersion = "4.38.0"; // Adjust SDK Version
|
||||||
|
|
@ -15,6 +18,8 @@ namespace Guru
|
||||||
public const string K_IAP_PURCHASE = "iap_purchase"; // 固定点位事件
|
public const string K_IAP_PURCHASE = "iap_purchase"; // 固定点位事件
|
||||||
public const string K_SUB_PURCHASE = "sub_purchase"; // 固定点位事件
|
public const string K_SUB_PURCHASE = "sub_purchase"; // 固定点位事件
|
||||||
|
|
||||||
|
private static Action<string> _onSessionSuccessCallback;
|
||||||
|
|
||||||
|
|
||||||
private static string _adId = "";
|
private static string _adId = "";
|
||||||
public static string AdId
|
public static string AdId
|
||||||
|
|
@ -45,7 +50,7 @@ namespace Guru
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="appToken"></param>
|
/// <param name="appToken"></param>
|
||||||
/// <param name="fbAppId">MIR 追踪 AppID</param>
|
/// <param name="fbAppId">MIR 追踪 AppID</param>
|
||||||
public static void StartService(string appToken, string fbAppId = "")
|
public static void StartService(string appToken, string fbAppId = "", Action<string> onSessionSuccess = null)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(appToken))
|
if (string.IsNullOrEmpty(appToken))
|
||||||
{
|
{
|
||||||
|
|
@ -53,6 +58,8 @@ namespace Guru
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_onSessionSuccessCallback = onSessionSuccess;
|
||||||
|
|
||||||
InstallEvent(IPMConfig.FIREBASE_ID, IPMConfig.IPM_DEVICE_ID); // 注入启动参数
|
InstallEvent(IPMConfig.FIREBASE_ID, IPMConfig.IPM_DEVICE_ID); // 注入启动参数
|
||||||
|
|
||||||
AdjustEnvironment environment = GetAdjustEnvironment();
|
AdjustEnvironment environment = GetAdjustEnvironment();
|
||||||
|
|
@ -61,6 +68,7 @@ namespace Guru
|
||||||
config.setDelayStart(DelayTime);
|
config.setDelayStart(DelayTime);
|
||||||
|
|
||||||
config.setPreinstallTrackingEnabled(true); // Adjust Preinstall
|
config.setPreinstallTrackingEnabled(true); // Adjust Preinstall
|
||||||
|
config.setSessionSuccessDelegate(OnSessionSuccessCallback); // SessionSuccess
|
||||||
|
|
||||||
#if UNITY_ANDROID
|
#if UNITY_ANDROID
|
||||||
if (!string.IsNullOrEmpty(fbAppId)) config.setFbAppId(fbAppId); // 注入 MIR ID
|
if (!string.IsNullOrEmpty(fbAppId)) config.setFbAppId(fbAppId); // 注入 MIR ID
|
||||||
|
|
@ -71,7 +79,7 @@ namespace Guru
|
||||||
config.setLogDelegate(log => LogI(LOG_TAG, log));
|
config.setLogDelegate(log => LogI(LOG_TAG, log));
|
||||||
config.setEventSuccessDelegate(OnEventSuccessCallback);
|
config.setEventSuccessDelegate(OnEventSuccessCallback);
|
||||||
config.setEventFailureDelegate(OnEventFailureCallback);
|
config.setEventFailureDelegate(OnEventFailureCallback);
|
||||||
config.setSessionSuccessDelegate(OnSessionSuccessCallback);
|
|
||||||
config.setSessionFailureDelegate(OnSessionFailureCallback);
|
config.setSessionFailureDelegate(OnSessionFailureCallback);
|
||||||
config.setAttributionChangedDelegate(OnAttributionChangedCallback);
|
config.setAttributionChangedDelegate(OnAttributionChangedCallback);
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -272,27 +280,10 @@ namespace Guru
|
||||||
|
|
||||||
private static void OnSessionSuccessCallback(AdjustSessionSuccess sessionSuccessData)
|
private static void OnSessionSuccessCallback(AdjustSessionSuccess sessionSuccessData)
|
||||||
{
|
{
|
||||||
LogI(LOG_TAG,"Session tracked successfully!");
|
LogI(LOG_TAG,$"{LOG_TAG} --- Session tracked successfully!");
|
||||||
|
|
||||||
if (sessionSuccessData.Message != null)
|
var adid = sessionSuccessData.Adid;
|
||||||
{
|
_onSessionSuccessCallback?.Invoke(adid);
|
||||||
LogI(LOG_TAG,"Message: " + sessionSuccessData.Message);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sessionSuccessData.Timestamp != null)
|
|
||||||
{
|
|
||||||
LogI(LOG_TAG,"Timestamp: " + sessionSuccessData.Timestamp);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sessionSuccessData.Adid != null)
|
|
||||||
{
|
|
||||||
LogI(LOG_TAG, "Adid: " + sessionSuccessData.Adid);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sessionSuccessData.JsonResponse != null)
|
|
||||||
{
|
|
||||||
LogI(LOG_TAG, "JsonResponse: " + sessionSuccessData.GetJsonResponse());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void OnSessionFailureCallback(AdjustSessionFailure sessionFailureData)
|
private static void OnSessionFailureCallback(AdjustSessionFailure sessionFailureData)
|
||||||
|
|
|
||||||
|
|
@ -79,7 +79,7 @@ namespace Guru
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 初始化平台
|
/// 初始化平台
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void Initialize()
|
public void Initialize(bool isDebug = false)
|
||||||
{
|
{
|
||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
Debug.Log($"<color=orange>=== Amazon will not init on Editor ===</color>");
|
Debug.Log($"<color=orange>=== Amazon will not init on Editor ===</color>");
|
||||||
|
|
@ -93,11 +93,9 @@ namespace Guru
|
||||||
// 初始化Amazon
|
// 初始化Amazon
|
||||||
Amazon.Initialize (AmazonAppID);
|
Amazon.Initialize (AmazonAppID);
|
||||||
Amazon.SetAdNetworkInfo(new AdNetworkInfo(DTBAdNetwork.MAX));
|
Amazon.SetAdNetworkInfo(new AdNetworkInfo(DTBAdNetwork.MAX));
|
||||||
#if UNITY_EDITOR || DEBUG
|
Debug.Log($"[Ads] --- Amazon init start isDebug:{isDebug}, AmazonID:{AmazonAppID}");
|
||||||
Amazon.EnableTesting (true); // Make sure to take this off when going live.
|
Amazon.EnableTesting (isDebug); // Make sure to take this off when going live.
|
||||||
#else
|
Amazon.EnableLogging (isDebug);
|
||||||
Amazon.EnableLogging (false);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if UNITY_IOS
|
#if UNITY_IOS
|
||||||
Amazon.SetAPSPublisherExtendedIdFeatureEnabled(true);
|
Amazon.SetAPSPublisherExtendedIdFeatureEnabled(true);
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,7 @@ namespace Guru
|
||||||
* before it can request an ad using OpenWrap SDK.
|
* before it can request an ad using OpenWrap SDK.
|
||||||
* The storeURL is the URL where users can download your app from the App Store/Google Play Store.
|
* The storeURL is the URL where users can download your app from the App Store/Google Play Store.
|
||||||
*/
|
*/
|
||||||
public void Initialize()
|
public void Initialize(bool isDebug = false)
|
||||||
{
|
{
|
||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
Debug.Log($"<color=orange>=== PubMatic will not init on Editor ===</color>");
|
Debug.Log($"<color=orange>=== PubMatic will not init on Editor ===</color>");
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ namespace Guru
|
||||||
protected override void InitService()
|
protected override void InitService()
|
||||||
{
|
{
|
||||||
base.InitService();
|
base.InitService();
|
||||||
InitChannels(); // 启动各广告渠道代理
|
InitChannels(_isDebug); // 启动各广告渠道代理
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
@ -37,14 +37,14 @@ namespace Guru
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 各渠道初始化
|
/// 各渠道初始化
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void InitChannels()
|
private void InitChannels(bool isDebug)
|
||||||
{
|
{
|
||||||
_adChannels = new HashSet<IAdChannel>();
|
_adChannels = new HashSet<IAdChannel>();
|
||||||
IAdChannel channel = null;
|
IAdChannel channel = null;
|
||||||
_asyncLoader = null;
|
_asyncLoader = null;
|
||||||
|
|
||||||
_chanelMax = new AdChanelMax(); // 默认持有MAXChannel
|
_chanelMax = new AdChanelMax(); // 默认持有MAXChannel
|
||||||
_chanelMax.Initialize();
|
_chanelMax.Initialize(isDebug);
|
||||||
if(_initSpec != null) _chanelMax.SetBannerBackColor(_initSpec.bannerColorHex);
|
if(_initSpec != null) _chanelMax.SetBannerBackColor(_initSpec.bannerColorHex);
|
||||||
|
|
||||||
//------------ 以下为扩展的广告渠道 ------------------
|
//------------ 以下为扩展的广告渠道 ------------------
|
||||||
|
|
@ -52,7 +52,7 @@ namespace Guru
|
||||||
// 开启渠道需要添加对应的宏
|
// 开启渠道需要添加对应的宏
|
||||||
|
|
||||||
channel = new AdChanelAmazon();
|
channel = new AdChanelAmazon();
|
||||||
channel.Initialize();
|
channel.Initialize(isDebug);
|
||||||
_adChannels.Add(channel); // Amazon
|
_adChannels.Add(channel); // Amazon
|
||||||
_asyncLoader = channel as IAsyncRequestChannel;
|
_asyncLoader = channel as IAsyncRequestChannel;
|
||||||
if (_asyncLoader != null)
|
if (_asyncLoader != null)
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,9 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using Guru;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
namespace Guru
|
namespace Guru
|
||||||
{
|
{
|
||||||
|
using System;
|
||||||
|
using UnityEngine;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
public abstract class ADServiceBase<T> : IADService where T : new()
|
public abstract class ADServiceBase<T> : IADService where T : new()
|
||||||
{
|
{
|
||||||
// 单利定义
|
// 单利定义
|
||||||
|
|
@ -23,6 +22,8 @@ namespace Guru
|
||||||
public bool IsInitialized => MaxSdk.IsInitialized() || _isServiceStarted;
|
public bool IsInitialized => MaxSdk.IsInitialized() || _isServiceStarted;
|
||||||
protected bool IsNetworkEnabled => Application.internetReachability != NetworkReachability.NotReachable;
|
protected bool IsNetworkEnabled => Application.internetReachability != NetworkReachability.NotReachable;
|
||||||
|
|
||||||
|
private const int MAX_ADS_RELOAD_INTERVAL = 6; // 广告加载最高时间为 2 的 6 次方 = 64秒
|
||||||
|
|
||||||
private bool _isServiceStarted;
|
private bool _isServiceStarted;
|
||||||
|
|
||||||
protected Action _onSdkInitReady;
|
protected Action _onSdkInitReady;
|
||||||
|
|
@ -33,10 +34,12 @@ namespace Guru
|
||||||
public static Action<string> OnInterstitialStartLoad;
|
public static Action<string> OnInterstitialStartLoad;
|
||||||
public static Action OnInterstitialLoaded;
|
public static Action OnInterstitialLoaded;
|
||||||
public static Action OnInterstitialFailed;
|
public static Action OnInterstitialFailed;
|
||||||
|
public static Action OnInterstitialClosed;
|
||||||
|
|
||||||
public static Action<string> OnRewardedStartLoad;
|
public static Action<string> OnRewardedStartLoad;
|
||||||
public static Action OnRewardLoaded;
|
public static Action OnRewardLoaded;
|
||||||
public static Action OnRewardFailed;
|
public static Action OnRewardFailed;
|
||||||
|
public static Action OnRewardClosed;
|
||||||
|
|
||||||
protected AdsModel _model;
|
protected AdsModel _model;
|
||||||
protected AdsInitSpec _initSpec = null;
|
protected AdsInitSpec _initSpec = null;
|
||||||
|
|
@ -50,6 +53,7 @@ namespace Guru
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal bool _isDebug = false;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 启动广告服务
|
/// 启动广告服务
|
||||||
|
|
@ -62,11 +66,23 @@ namespace Guru
|
||||||
if (IsInitialized) return; // 已经初始化后, 无需再次初始化
|
if (IsInitialized) return; // 已经初始化后, 无需再次初始化
|
||||||
|
|
||||||
_initSpec = initSpec;
|
_initSpec = initSpec;
|
||||||
|
if (_initSpec == null) _initSpec = AdsInitSpec.BuildDefault();
|
||||||
|
|
||||||
|
_isDebug = _initSpec.isDebug;
|
||||||
_isServiceStarted = true;
|
_isServiceStarted = true;
|
||||||
_onSdkInitReady = callback;
|
_onSdkInitReady = callback;
|
||||||
if(_model == null) _model = AdsModel.Create();
|
if(_model == null) _model = AdsModel.Create();
|
||||||
this.Log("AD SDK Start Init");
|
this.Log("AD SDK Start Init");
|
||||||
|
|
||||||
|
InitMaxCallbacks(); // 初始化 MAX 广告
|
||||||
|
InitService(); // 内部继承接口
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 初始化 MAX 广告组件
|
||||||
|
/// </summary>
|
||||||
|
private void InitMaxCallbacks()
|
||||||
|
{
|
||||||
//-------------- 初始化回调 ------------------
|
//-------------- 初始化回调 ------------------
|
||||||
MaxSdkCallbacks.OnSdkInitializedEvent += OnMaxSdkInitializedCallBack;
|
MaxSdkCallbacks.OnSdkInitializedEvent += OnMaxSdkInitializedCallBack;
|
||||||
MaxSdkCallbacks.Interstitial.OnAdRevenuePaidEvent += OnAdRevenuePaidEvent;
|
MaxSdkCallbacks.Interstitial.OnAdRevenuePaidEvent += OnAdRevenuePaidEvent;
|
||||||
|
|
@ -94,10 +110,7 @@ namespace Guru
|
||||||
MaxSdkCallbacks.Rewarded.OnAdReceivedRewardEvent += OnRewardedAdReceivedRewardEvent;
|
MaxSdkCallbacks.Rewarded.OnAdReceivedRewardEvent += OnRewardedAdReceivedRewardEvent;
|
||||||
|
|
||||||
//-------------- SDK 初始化 -------------------
|
//-------------- SDK 初始化 -------------------
|
||||||
if (_initSpec == null) _initSpec = AdsInitSpec.BuildDefault();
|
MaxSdk.SetExtraParameter("enable_black_screen_fixes", "true"); // 修复黑屏
|
||||||
MaxSdk.SetVerboseLogging(_initSpec.isDebug);
|
|
||||||
|
|
||||||
InitService(); // 内部继承接口
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void InitService()
|
protected virtual void InitService()
|
||||||
|
|
@ -138,6 +151,13 @@ namespace Guru
|
||||||
set => Model.BuyNoAds = value;
|
set => Model.BuyNoAds = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private float GetRetryDelaySeconds(int retryCount)
|
||||||
|
{
|
||||||
|
// 最低 2^retryCount 秒
|
||||||
|
// 最高 2^6 = 64 秒
|
||||||
|
return (float)Math.Pow(2, Math.Min(MAX_ADS_RELOAD_INTERVAL, retryCount));
|
||||||
|
}
|
||||||
|
|
||||||
#region Lifecycele
|
#region Lifecycele
|
||||||
|
|
||||||
public void OnAppPaused(bool paused)
|
public void OnAppPaused(bool paused)
|
||||||
|
|
@ -417,7 +437,7 @@ namespace Guru
|
||||||
private string _iadsCategory = "main";
|
private string _iadsCategory = "main";
|
||||||
private int _interstitialRetryAttempt;
|
private int _interstitialRetryAttempt;
|
||||||
protected float _iadsLoadStartTime;
|
protected float _iadsLoadStartTime;
|
||||||
private Action _interstitialDismissAction;
|
private Action _interCloseAction;
|
||||||
protected bool _isIadsLoading = false;
|
protected bool _isIadsLoading = false;
|
||||||
public bool IsIadsLoading => _isIadsLoading;
|
public bool IsIadsLoading => _isIadsLoading;
|
||||||
|
|
||||||
|
|
@ -473,7 +493,7 @@ namespace Guru
|
||||||
}
|
}
|
||||||
|
|
||||||
_iadsCategory = category;
|
_iadsCategory = category;
|
||||||
_interstitialDismissAction = dismissAction;
|
_interCloseAction = dismissAction;
|
||||||
MaxSdk.ShowInterstitial(GetInterstitialID());
|
MaxSdk.ShowInterstitial(GetInterstitialID());
|
||||||
|
|
||||||
// RequestInterstitialAD(); // 直接加载下一个广告
|
// RequestInterstitialAD(); // 直接加载下一个广告
|
||||||
|
|
@ -500,8 +520,8 @@ namespace Guru
|
||||||
this.LogError(
|
this.LogError(
|
||||||
$"OnInterstitialFailedEvent AdLoadFailureInfo:{errorInfo.AdLoadFailureInfo}, Message: {errorInfo.Message}");
|
$"OnInterstitialFailedEvent AdLoadFailureInfo:{errorInfo.AdLoadFailureInfo}, Message: {errorInfo.Message}");
|
||||||
_interstitialRetryAttempt++;
|
_interstitialRetryAttempt++;
|
||||||
double retryDelay = Math.Pow(2, Math.Min(3, _interstitialRetryAttempt));
|
float retryDelay = GetRetryDelaySeconds(_interstitialRetryAttempt);
|
||||||
DelayCall((float)retryDelay, RequestInterstitialAD);
|
DelayCall(retryDelay, RequestInterstitialAD);
|
||||||
// Analytics.ADIadsFailed(adUnitId, (int)errorInfo.Code, GetAdsLoadDuration(ref _iadsLoadStartTime), _iadsCategory);
|
// Analytics.ADIadsFailed(adUnitId, (int)errorInfo.Code, GetAdsLoadDuration(ref _iadsLoadStartTime), _iadsCategory);
|
||||||
Analytics.ADIadsFailed(AdParams.Build(adUnitId,
|
Analytics.ADIadsFailed(AdParams.Build(adUnitId,
|
||||||
duration: GetAdsLoadDuration(ref _iadsLoadStartTime), category: _iadsCategory,
|
duration: GetAdsLoadDuration(ref _iadsLoadStartTime), category: _iadsCategory,
|
||||||
|
|
@ -540,7 +560,8 @@ namespace Guru
|
||||||
protected virtual void OnInterstitialDismissedEvent(string adUnitId, MaxSdkBase.AdInfo adInfo)
|
protected virtual void OnInterstitialDismissedEvent(string adUnitId, MaxSdkBase.AdInfo adInfo)
|
||||||
{
|
{
|
||||||
// Interstitial ad is hidden. Pre-load the next ad
|
// Interstitial ad is hidden. Pre-load the next ad
|
||||||
_interstitialDismissAction?.Invoke();
|
_interCloseAction?.Invoke();
|
||||||
|
OnInterstitialClosed?.Invoke();
|
||||||
// Analytics.ADIadsClose(adUnitId, _iadsCategory);
|
// Analytics.ADIadsClose(adUnitId, _iadsCategory);
|
||||||
Analytics.ADIadsClose(AdParams.Build(adUnitId, category: _iadsCategory));
|
Analytics.ADIadsClose(AdParams.Build(adUnitId, category: _iadsCategory));
|
||||||
//延时加载下一个广告
|
//延时加载下一个广告
|
||||||
|
|
@ -554,9 +575,9 @@ namespace Guru
|
||||||
private string _rewardCategory = "main";
|
private string _rewardCategory = "main";
|
||||||
private int _rewardRetryAttempt;
|
private int _rewardRetryAttempt;
|
||||||
protected float _radsLoadStartTime;
|
protected float _radsLoadStartTime;
|
||||||
private Action _rewardAction;
|
private Action _rvRewardAction;
|
||||||
private Action<string> _failAction;
|
private Action<string> _rvFailAction;
|
||||||
private Action _dismissAction;
|
private Action _rvDismissAction;
|
||||||
protected bool _isRadsLoading = false;
|
protected bool _isRadsLoading = false;
|
||||||
public bool IsRadsLoading => _isRadsLoading;
|
public bool IsRadsLoading => _isRadsLoading;
|
||||||
|
|
||||||
|
|
@ -620,9 +641,9 @@ namespace Guru
|
||||||
}
|
}
|
||||||
|
|
||||||
_rewardCategory = category;
|
_rewardCategory = category;
|
||||||
_rewardAction = rewardAction;
|
_rvRewardAction = rewardAction;
|
||||||
_failAction = failAction;
|
_rvFailAction = failAction;
|
||||||
_dismissAction = dismissAction;
|
_rvDismissAction = dismissAction;
|
||||||
MaxSdk.ShowRewardedAd(GetRewardedID());
|
MaxSdk.ShowRewardedAd(GetRewardedID());
|
||||||
|
|
||||||
// RequestRewardedAD();
|
// RequestRewardedAD();
|
||||||
|
|
@ -657,8 +678,8 @@ namespace Guru
|
||||||
errorCode: (int)errorInfo.Code,
|
errorCode: (int)errorInfo.Code,
|
||||||
waterfallName: errorInfo?.WaterfallInfo?.Name ?? ""));
|
waterfallName: errorInfo?.WaterfallInfo?.Name ?? ""));
|
||||||
_rewardRetryAttempt++;
|
_rewardRetryAttempt++;
|
||||||
double retryDelay = Math.Pow(2, Math.Min(3, _rewardRetryAttempt));
|
float retryDelay = GetRetryDelaySeconds(_rewardRetryAttempt);
|
||||||
DelayCall((float)retryDelay, RequestRewardedAD);
|
DelayCall(retryDelay, RequestRewardedAD);
|
||||||
|
|
||||||
OnRewardFailed?.Invoke();
|
OnRewardFailed?.Invoke();
|
||||||
}
|
}
|
||||||
|
|
@ -674,7 +695,7 @@ namespace Guru
|
||||||
duration: GetAdsLoadDuration(ref _radsLoadStartTime), category: _rewardCategory,
|
duration: GetAdsLoadDuration(ref _radsLoadStartTime), category: _rewardCategory,
|
||||||
errorCode: (int)errorInfo.Code,
|
errorCode: (int)errorInfo.Code,
|
||||||
waterfallName: errorInfo?.WaterfallInfo?.Name ?? ""));
|
waterfallName: errorInfo?.WaterfallInfo?.Name ?? ""));
|
||||||
_failAction?.Invoke("OnRewardedAdFailedToDisplayEvent");
|
_rvFailAction?.Invoke("OnRewardedAdFailedToDisplayEvent");
|
||||||
DelayCall(2.0f, RequestRewardedAD);
|
DelayCall(2.0f, RequestRewardedAD);
|
||||||
|
|
||||||
OnRewardFailed?.Invoke();
|
OnRewardFailed?.Invoke();
|
||||||
|
|
@ -697,11 +718,17 @@ namespace Guru
|
||||||
protected virtual void OnRewardedAdDismissedEvent(string adUnitId, MaxSdkBase.AdInfo adInfo)
|
protected virtual void OnRewardedAdDismissedEvent(string adUnitId, MaxSdkBase.AdInfo adInfo)
|
||||||
{
|
{
|
||||||
this.Log("OnRewardedAdDismissedEvent");
|
this.Log("OnRewardedAdDismissedEvent");
|
||||||
|
|
||||||
|
_rvDismissAction?.Invoke();
|
||||||
|
OnRewardClosed?.Invoke();
|
||||||
|
|
||||||
// Analytics.ADRadsClose(adUnitId, _rewardCategory);
|
// Analytics.ADRadsClose(adUnitId, _rewardCategory);
|
||||||
Analytics.ADRadsClose(AdParams.Build(adUnitId, category: _rewardCategory));
|
Analytics.ADRadsClose(AdParams.Build(adUnitId, category: _rewardCategory));
|
||||||
_dismissAction?.Invoke();
|
|
||||||
//延时加载下一个广告
|
//延时加载下一个广告
|
||||||
DelayCall(2.0f, RequestRewardedAD);
|
DelayCall(2.0f, RequestRewardedAD);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void OnRewardedAdReceivedRewardEvent(string adUnitId, MaxSdk.Reward reward,
|
protected virtual void OnRewardedAdReceivedRewardEvent(string adUnitId, MaxSdk.Reward reward,
|
||||||
|
|
@ -711,7 +738,7 @@ namespace Guru
|
||||||
// Analytics.ADRadsRewarded(adUnitId, _rewardCategory);
|
// Analytics.ADRadsRewarded(adUnitId, _rewardCategory);
|
||||||
Analytics.ADRadsRewarded(AdParams.Build(adUnitId, category: _rewardCategory));
|
Analytics.ADRadsRewarded(AdParams.Build(adUnitId, category: _rewardCategory));
|
||||||
// Rewarded ad was displayed and user should receive the reward
|
// Rewarded ad was displayed and user should receive the reward
|
||||||
_rewardAction?.Invoke();
|
_rvRewardAction?.Invoke();
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
|
||||||
|
|
@ -32,10 +32,11 @@ namespace Guru
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// MAX 渠道初始化, 启动服务
|
/// MAX 渠道初始化, 启动服务
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void Initialize()
|
public void Initialize(bool isDebug = false)
|
||||||
{
|
{
|
||||||
MaxSdk.SetSdkKey(GuruSettings.Instance.ADSetting.SDK_KEY);
|
MaxSdk.SetSdkKey(GuruSettings.Instance.ADSetting.SDK_KEY);
|
||||||
MaxSdk.SetUserId(IPMConfig.IPM_UID); // 上报用户ID
|
MaxSdk.SetUserId(IPMConfig.IPM_UID); // 上报用户ID
|
||||||
|
MaxSdk.SetVerboseLogging(isDebug); // 设置调试数据
|
||||||
MaxSdk.InitializeSdk();
|
MaxSdk.InitializeSdk();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ namespace Guru
|
||||||
{
|
{
|
||||||
// Action<string> OnRequestOver { get; set; }
|
// Action<string> OnRequestOver { get; set; }
|
||||||
|
|
||||||
void Initialize();
|
void Initialize(bool isDebug = false);
|
||||||
|
|
||||||
string Name { get;}
|
string Name { get;}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -295,9 +295,11 @@ namespace Guru
|
||||||
/// <param name="orderId"></param>
|
/// <param name="orderId"></param>
|
||||||
/// <param name="orderType"></param>
|
/// <param name="orderType"></param>
|
||||||
/// <param name="timestamp"></param>
|
/// <param name="timestamp"></param>
|
||||||
public static void Tch001IAPRev(double value, string productId, string orderId, string orderType, string timestamp)
|
/// <param name="isTest"></param>
|
||||||
|
public static void Tch001IAPRev(double value, string productId, string orderId, string orderType, string timestamp, bool isTest = false)
|
||||||
{
|
{
|
||||||
TchRevEvent(EventTchAdRev001Impression, IAPPlatform, value, orderType, productId, orderId, timestamp);
|
string sandbox = isTest ? "true" : "false";
|
||||||
|
TchRevEvent(EventTchAdRev001Impression, IAPPlatform, value, orderType, productId, orderId, timestamp, sandbox);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -309,11 +311,13 @@ namespace Guru
|
||||||
/// <param name="orderId"></param>
|
/// <param name="orderId"></param>
|
||||||
/// <param name="orderType"></param>
|
/// <param name="orderType"></param>
|
||||||
/// <param name="timestamp"></param>
|
/// <param name="timestamp"></param>
|
||||||
|
/// <param name="isTest"></param>
|
||||||
// public static void Tch02IAPRev(double value, string productId, string orderId, string orderType, string timestamp)
|
// public static void Tch02IAPRev(double value, string productId, string orderId, string orderType, string timestamp)
|
||||||
public static void Tch02IAPRev(double value, string productId, string orderId, string orderType, string timestamp)
|
public static void Tch02IAPRev(double value, string productId, string orderId, string orderType, string timestamp, bool isTest = false)
|
||||||
{
|
{
|
||||||
if (!EnableTch02Event) return;
|
if (!EnableTch02Event) return;
|
||||||
TchRevEvent(EventTchAdRev02Impression, IAPPlatform, value, orderType, productId, orderId, timestamp);
|
string sandbox = isTest ? "true" : "false";
|
||||||
|
TchRevEvent(EventTchAdRev02Impression, IAPPlatform, value, orderType, productId, orderId, timestamp, sandbox);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -362,8 +366,9 @@ namespace Guru
|
||||||
/// <param name="productId"></param>
|
/// <param name="productId"></param>
|
||||||
/// <param name="orderId"></param>
|
/// <param name="orderId"></param>
|
||||||
/// <param name="timestamp"></param>
|
/// <param name="timestamp"></param>
|
||||||
|
/// <param name="sandbox"></param>
|
||||||
private static void TchRevEvent(string evtName, string platform, double value,
|
private static void TchRevEvent(string evtName, string platform, double value,
|
||||||
string orderType = "", string productId = "", string orderId = "", string timestamp = "")
|
string orderType = "", string productId = "", string orderId = "", string timestamp = "", string sandbox = "")
|
||||||
{
|
{
|
||||||
var data = new Dictionary<string, dynamic>()
|
var data = new Dictionary<string, dynamic>()
|
||||||
{
|
{
|
||||||
|
|
@ -373,10 +378,13 @@ namespace Guru
|
||||||
};
|
};
|
||||||
|
|
||||||
//--------- Extra data for IAP receipt ---------------
|
//--------- Extra data for IAP receipt ---------------
|
||||||
|
|
||||||
if(!string.IsNullOrEmpty(orderType)) data["order_type"] = orderType;
|
if(!string.IsNullOrEmpty(orderType)) data["order_type"] = orderType;
|
||||||
if(!string.IsNullOrEmpty(productId)) data["product_id"] = productId;
|
if(!string.IsNullOrEmpty(productId)) data["product_id"] = productId;
|
||||||
if(!string.IsNullOrEmpty(orderId)) data["order_id"] = orderId;
|
if(!string.IsNullOrEmpty(orderId)) data["order_id"] = orderId;
|
||||||
if(!string.IsNullOrEmpty(timestamp)) data["trans_ts"] = timestamp;
|
if(!string.IsNullOrEmpty(timestamp)) data["trans_ts"] = timestamp;
|
||||||
|
if(!string.IsNullOrEmpty(sandbox)) data["sandbox"] = sandbox;
|
||||||
|
|
||||||
//--------- Extra data for IAP receipt ---------------
|
//--------- Extra data for IAP receipt ---------------
|
||||||
|
|
||||||
LogEvent(evtName, data);
|
LogEvent(evtName, data);
|
||||||
|
|
@ -603,15 +611,19 @@ namespace Guru
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="productId"></param>
|
/// <param name="productId"></param>
|
||||||
/// <param name="usdPrice"></param>
|
/// <param name="usdPrice"></param>
|
||||||
/// <param name="userCurrency"></param>
|
/// <param name="orderData"></param>
|
||||||
/// <param name="payPrice"></param>
|
/// <param name="isTest"></param>
|
||||||
/// <param name="orderId"></param>
|
public static void ReportIAPSuccessEvent(BaseOrderData orderData, double usdPrice, bool isTest = false)
|
||||||
/// <param name="orderType"></param>
|
|
||||||
/// <param name="orderDate"></param>
|
|
||||||
/// <param name="scene"></param>
|
|
||||||
/// <param name="isFree"></param>
|
|
||||||
public static void ReportIAPSuccessEvent(double usdPrice, string productId, BaseOrderData orderData)
|
|
||||||
{
|
{
|
||||||
|
if (orderData == null) return;
|
||||||
|
|
||||||
|
if (!isTest && usdPrice == 0)
|
||||||
|
{
|
||||||
|
Debug.Log($"[SDK] --- Pruchase value is 0, skip report orders");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
string productId = orderData.productId;
|
||||||
string userCurrency = orderData.userCurrency;
|
string userCurrency = orderData.userCurrency;
|
||||||
double payPrice = orderData.payPrice;
|
double payPrice = orderData.payPrice;
|
||||||
string orderType = orderData.OrderType();
|
string orderType = orderData.OrderType();
|
||||||
|
|
@ -636,21 +648,23 @@ namespace Guru
|
||||||
}
|
}
|
||||||
|
|
||||||
// TCH 001
|
// TCH 001
|
||||||
Tch001IAPRev(usdPrice, productId, orderId, orderType, orderDate);
|
Tch001IAPRev(usdPrice, productId, orderId, orderType, orderDate, isTest);
|
||||||
|
|
||||||
// TCH 020
|
// TCH 020
|
||||||
Tch02IAPRev(usdPrice, productId, orderId, orderType, orderDate);
|
Tch02IAPRev(usdPrice, productId, orderId, orderType, orderDate, isTest);
|
||||||
|
|
||||||
// Facebook Track IAP Purchase
|
// Facebook Track IAP Purchase
|
||||||
FBPurchase(usdPrice, USD, "iap", IAPPlatform);
|
FBPurchase(usdPrice, USD, "iap", IAPPlatform);
|
||||||
|
|
||||||
if (orderData.orderType == 1)
|
if (orderData.orderType == 1)
|
||||||
{
|
{
|
||||||
// sub_pruchase : Firebase + Guru + Adjust
|
// sub_pruchase : Firebase + Guru + Adjust
|
||||||
SubPurchase(usdPrice, productId, orderId, orderDate, productToken, receipt);
|
SubPurchase(usdPrice, productId, orderId, orderDate, productToken, receipt, isTest);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// iap_purchase : Firebase + Guru + Adjust
|
// iap_purchase : Firebase + Guru + Adjust
|
||||||
IAPPurchase(usdPrice, productId, orderId, orderDate, productToken, receipt);
|
IAPPurchase(usdPrice, productId, orderId, orderDate, productToken, receipt, isTest);
|
||||||
}
|
}
|
||||||
|
|
||||||
// IAP Ret true : Firebase + Guru + Adjust
|
// IAP Ret true : Firebase + Guru + Adjust
|
||||||
|
|
@ -669,21 +683,33 @@ namespace Guru
|
||||||
/// <param name="productId"></param>
|
/// <param name="productId"></param>
|
||||||
/// <param name="orderId"></param>
|
/// <param name="orderId"></param>
|
||||||
/// <param name="orderDate"></param>
|
/// <param name="orderDate"></param>
|
||||||
|
/// <param name="purchaseToken"></param>
|
||||||
|
/// <param name="receipt"></param>
|
||||||
|
/// <param name="isSandbox"></param>
|
||||||
public static void IAPPurchase(double value, string productId, string orderId, string orderDate,
|
public static void IAPPurchase(double value, string productId, string orderId, string orderDate,
|
||||||
string purchaseToken = "", string receipt = "")
|
string purchaseToken = "", string receipt = "", bool isSandbox = false)
|
||||||
{
|
{
|
||||||
IAPPurchaseReport(EventIAPPurchase, value, productId, orderId, "IAP", orderDate, purchaseToken, receipt);
|
IAPPurchaseReport(EventIAPPurchase, value, productId, orderId, "IAP", orderDate, purchaseToken, receipt, isSandbox);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// SUB 订阅上报
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value"></param>
|
||||||
|
/// <param name="productId"></param>
|
||||||
|
/// <param name="orderId"></param>
|
||||||
|
/// <param name="orderDate"></param>
|
||||||
|
/// <param name="purchaseToken"></param>
|
||||||
|
/// <param name="receipt"></param>
|
||||||
|
/// <param name="isSandbox"></param>
|
||||||
public static void SubPurchase(double value, string productId, string orderId, string orderDate,
|
public static void SubPurchase(double value, string productId, string orderId, string orderDate,
|
||||||
string purchaseToken = "", string receipt = "")
|
string purchaseToken = "", string receipt = "", bool isSandbox = false)
|
||||||
{
|
{
|
||||||
IAPPurchaseReport(EventSubPurchase, value, productId, orderId, "SUB", orderDate, purchaseToken, receipt);
|
IAPPurchaseReport(EventSubPurchase, value, productId, orderId, "SUB", orderDate, purchaseToken, receipt, isSandbox);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void IAPPurchaseReport(string eventName, double value, string productId,
|
||||||
private static void IAPPurchaseReport(string eventName, double value, string productId, string orderId, string orderType, string orderDate,
|
string orderId, string orderType, string orderDate, string purchaseToken = "", string receipt = "", bool isSandbox = false)
|
||||||
string purchaseToken = "", string receipt = "")
|
|
||||||
{
|
{
|
||||||
|
|
||||||
var dict = new Dictionary<string, dynamic>()
|
var dict = new Dictionary<string, dynamic>()
|
||||||
|
|
@ -694,20 +720,17 @@ namespace Guru
|
||||||
[ParameterProductId] = productId,
|
[ParameterProductId] = productId,
|
||||||
["order_id"] = orderId,
|
["order_id"] = orderId,
|
||||||
["order_type"] = orderType,
|
["order_type"] = orderType,
|
||||||
["trans_ts"] = orderDate
|
["trans_ts"] = orderDate,
|
||||||
|
["sandbox"] = isSandbox? "true": "false"
|
||||||
};
|
};
|
||||||
|
|
||||||
// 上报Firebase + 自打点
|
|
||||||
LogEvent(eventName, dict, new EventSetting() { EnableFirebaseAnalytics = true, });
|
|
||||||
|
|
||||||
|
|
||||||
|
// 上报Firebase + 自打点
|
||||||
|
LogEvent(eventName, dict, new EventSetting() { EnableFirebaseAnalytics = true });
|
||||||
|
|
||||||
// 上报 Adjust 支付事件
|
// 上报 Adjust 支付事件
|
||||||
// if (value > 0)
|
|
||||||
// {
|
|
||||||
// 根据事件名称来获取对应的事件Token(iap_purchase/sub_purchase)
|
|
||||||
LogAdjustRevenueEvent(eventName, value, productId, orderId, purchaseToken, receipt, dict);
|
LogAdjustRevenueEvent(eventName, value, productId, orderId, purchaseToken, receipt, dict);
|
||||||
// }
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
namespace Guru
|
namespace Guru
|
||||||
{
|
{
|
||||||
|
|
@ -8,6 +7,7 @@ namespace Guru
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using com.adjust.sdk;
|
using com.adjust.sdk;
|
||||||
using Facebook.Unity;
|
using Facebook.Unity;
|
||||||
|
using UnityEngine;
|
||||||
using Firebase.Analytics;
|
using Firebase.Analytics;
|
||||||
using Firebase.Crashlytics;
|
using Firebase.Crashlytics;
|
||||||
|
|
||||||
|
|
@ -180,9 +180,9 @@ namespace Guru
|
||||||
/// <param name="eventName"></param>
|
/// <param name="eventName"></param>
|
||||||
/// <param name="extras"></param>
|
/// <param name="extras"></param>
|
||||||
/// <param name="eventSetting"></param>
|
/// <param name="eventSetting"></param>
|
||||||
|
/// <param name="priority"></param>
|
||||||
internal static void LogEvent(string eventName, Dictionary<string, dynamic> extras, EventSetting eventSetting = null, int priority = -1)
|
internal static void LogEvent(string eventName, Dictionary<string, dynamic> extras, EventSetting eventSetting = null, int priority = -1)
|
||||||
{
|
{
|
||||||
Log.I(TAG, $"eventName:{eventName}, params:{string.Join(",", extras)}");
|
|
||||||
CustomLogEvent(eventName, extras, priority); // 自定义打点上报
|
CustomLogEvent(eventName, extras, priority); // 自定义打点上报
|
||||||
CheckLogCache(eventName, extras, eventSetting); // log缓存和消费
|
CheckLogCache(eventName, extras, eventSetting); // log缓存和消费
|
||||||
|
|
||||||
|
|
@ -194,7 +194,10 @@ namespace Guru
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
eventSetting ??= _defaultEventSetting;
|
string paramStr = string.Join(",", extras);
|
||||||
|
Log.I(TAG, $"eventName:{eventName}, params:{paramStr}");
|
||||||
|
|
||||||
|
if (eventSetting == null) eventSetting = _defaultEventSetting;
|
||||||
if (eventSetting.EnableFirebaseAnalytics)
|
if (eventSetting.EnableFirebaseAnalytics)
|
||||||
{
|
{
|
||||||
List<Parameter> parameters = new List<Parameter>();
|
List<Parameter> parameters = new List<Parameter>();
|
||||||
|
|
@ -216,7 +219,6 @@ namespace Guru
|
||||||
parameters.Add(new Parameter(kv.Key, decimal.ToDouble(decimalValue)));
|
parameters.Add(new Parameter(kv.Key, decimal.ToDouble(decimalValue)));
|
||||||
else
|
else
|
||||||
parameters.Add(new Parameter(kv.Key, kv.Value.ToString()));
|
parameters.Add(new Parameter(kv.Key, kv.Value.ToString()));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FirebaseAnalytics.LogEvent(eventName, parameters.ToArray());
|
FirebaseAnalytics.LogEvent(eventName, parameters.ToArray());
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,10 @@ namespace Guru
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// return JsonMapper.ToObject<T>(jsonStr);
|
// return JsonMapper.ToObject<T>(jsonStr);
|
||||||
return JsonConvert.DeserializeObject<T>(jsonStr);
|
return JsonConvert.DeserializeObject<T>(jsonStr, new JsonSerializerSettings()
|
||||||
|
{
|
||||||
|
ObjectCreationHandling = ObjectCreationHandling.Replace,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using Firebase;
|
using Firebase;
|
||||||
using Firebase.Analytics;
|
using Firebase.Analytics;
|
||||||
using Firebase.Extensions;
|
using Firebase.Extensions;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
namespace Guru
|
namespace Guru
|
||||||
{
|
{
|
||||||
|
|
@ -117,10 +117,34 @@ namespace Guru
|
||||||
// 启动 AdjustService
|
// 启动 AdjustService
|
||||||
string appToken = GuruSettings.Instance.AdjustSetting?.GetAppToken() ?? "";
|
string appToken = GuruSettings.Instance.AdjustSetting?.GetAppToken() ?? "";
|
||||||
string fbAppId = GuruSettings.Instance.IPMSetting.FacebookAppId;
|
string fbAppId = GuruSettings.Instance.IPMSetting.FacebookAppId;
|
||||||
AdjustService.StartService(appToken, fbAppId);
|
|
||||||
|
if (!string.IsNullOrEmpty(IPMConfig.ADJUST_ID))
|
||||||
|
{
|
||||||
|
ReportAdjustId(IPMConfig.ADJUST_ID); // 二次启动后,若有值则立即上报属性
|
||||||
|
}
|
||||||
|
|
||||||
|
AdjustService.StartService(appToken, fbAppId, adjustId =>
|
||||||
|
{
|
||||||
|
// 获取 ADID
|
||||||
|
if (string.IsNullOrEmpty(adjustId))
|
||||||
|
{
|
||||||
|
adjustId = "not_set";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
IPMConfig.ADJUST_ID = adjustId;
|
||||||
|
}
|
||||||
|
ReportAdjustId(adjustId);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static void ReportAdjustId(string adjustId)
|
||||||
|
{
|
||||||
|
FirebaseAnalytics.SetUserProperty("adjust_id", adjustId); // 仅上报 Firebase 用户属性
|
||||||
|
Debug.Log($"[SDK] --- Firebase + Adjust ID: {adjustId}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,7 @@ namespace Guru
|
||||||
{
|
{
|
||||||
GenDeviceId();
|
GenDeviceId();
|
||||||
}
|
}
|
||||||
|
|
||||||
return SavedDeviceId; // 优先使用缓存的 DeviceID
|
return SavedDeviceId; // 优先使用缓存的 DeviceID
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -34,19 +34,14 @@ namespace Guru
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
Debug.Log($"[IAP] --- Apple Order Response: {response}");
|
||||||
ResponseData<OrderResponse> responseData = JsonUtility.FromJson<ResponseData<OrderResponse>>(response);
|
ResponseData<OrderResponse> responseData = JsonUtility.FromJson<ResponseData<OrderResponse>>(response);
|
||||||
if (responseData != null && responseData.data != null)
|
if (responseData != null && responseData.data != null)
|
||||||
{
|
{
|
||||||
double usdPrice = responseData.data.usdPrice;
|
double usdPrice = responseData.data.usdPrice;
|
||||||
string productId = orderData.productId;
|
bool isTest = responseData.data.test;
|
||||||
|
|
||||||
// Analytics.Tch001IAPRev(usdPrice, productId, orderData.orderId, orderData.OrderType(), orderData.payedDate);
|
Analytics.ReportIAPSuccessEvent(orderData, usdPrice, isTest);
|
||||||
// Analytics.Tch02IAPRev(usdPrice);
|
|
||||||
//
|
|
||||||
// AdjustService.TrackSubPurchase(usdPrice, productId);
|
|
||||||
// Analytics.SubPurchase(usdPrice, productId);
|
|
||||||
|
|
||||||
Analytics.ReportIAPSuccessEvent(usdPrice, productId, orderData);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
|
|
||||||
|
|
@ -31,21 +31,14 @@ namespace Guru
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
Debug.Log($"[IAP] --- Google Order Response: {response}");
|
||||||
ResponseData<OrderResponse> responseData = JsonUtility.FromJson<ResponseData<OrderResponse>>(response);
|
ResponseData<OrderResponse> responseData = JsonUtility.FromJson<ResponseData<OrderResponse>>(response);
|
||||||
if (responseData != null && responseData.data != null)
|
if (responseData != null && responseData.data != null)
|
||||||
{
|
{
|
||||||
double usdPrice = responseData.data.usdPrice;
|
double usdPrice = responseData.data.usdPrice;
|
||||||
string productId = orderData.RealProductId;
|
bool isTest = responseData.data.test;
|
||||||
|
|
||||||
// Analytics.Tch001IAPRev(usdPrice, productId, orderId, orderType, orderDate); // TCH 001
|
Analytics.ReportIAPSuccessEvent(orderData, usdPrice, isTest);
|
||||||
// // Analytics.Tch02IAPRev(usdPrice, productId, orderId, orderTypeString, timestamp);
|
|
||||||
// Analytics.Tch02IAPRev(usdPrice); // TCH 020
|
|
||||||
//
|
|
||||||
// // Adjust Track IAP Purchase
|
|
||||||
// AdjustService.TrackIAPPurchase(usdPrice, productId); // 上报 IAP 支付事件
|
|
||||||
// Analytics.IAPPurchase(usdPrice, productId);
|
|
||||||
|
|
||||||
Analytics.ReportIAPSuccessEvent(usdPrice, productId, orderData);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
|
|
||||||
|
|
@ -6,10 +6,12 @@ namespace Guru
|
||||||
public class OrderResponse
|
public class OrderResponse
|
||||||
{
|
{
|
||||||
public double usdPrice;
|
public double usdPrice;
|
||||||
|
public bool test;
|
||||||
|
public string state;
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
return $"{nameof(usdPrice)}: {usdPrice}";
|
return $"{nameof(usdPrice)}: {usdPrice} {nameof(test)}: {test} {nameof(state)}: {state}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 1fef034d48ac449fb99531b40139954e
|
||||||
|
timeCreated: 1718844748
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 8c0dd2d4b63445c2828e05c10274d672
|
||||||
|
timeCreated: 1718845536
|
||||||
|
|
@ -0,0 +1,178 @@
|
||||||
|
|
||||||
|
|
||||||
|
#if UNITY_ANDROID
|
||||||
|
|
||||||
|
namespace Guru.Notification
|
||||||
|
{
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using UnityEditor.Android;
|
||||||
|
using System.Xml;
|
||||||
|
|
||||||
|
public class PostCustomActivity: IPostGenerateGradleAndroidProject
|
||||||
|
{
|
||||||
|
private const int POST_ORDER = 10;
|
||||||
|
private const string K_PREMISSION_POST_NOTIFICATIONS = "android.permission.POST_NOTIFICATIONS";
|
||||||
|
private const string K_CUSTOM_NOTIFICATION_ACTIVITY = "custom_notification_android_activity";
|
||||||
|
private const string V_DEFAULT_GURU_ACTIVITY = "com.google.firebase.messaging.MessageForwardingService";
|
||||||
|
const string K_ANDROID_NAMESPACE_URI = "http://schemas.android.com/apk/res/android";
|
||||||
|
|
||||||
|
public int callbackOrder => POST_ORDER;
|
||||||
|
|
||||||
|
public void OnPostGenerateGradleAndroidProject(string path)
|
||||||
|
{
|
||||||
|
SetupAndroidManifest(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 设置 Android Manifest
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="projectPath"></param>
|
||||||
|
/// <exception cref="FileNotFoundException"></exception>
|
||||||
|
private void SetupAndroidManifest(string projectPath)
|
||||||
|
{
|
||||||
|
var manifestPath = $"{projectPath}/src/main/AndroidManifest.xml";
|
||||||
|
if (!File.Exists(manifestPath))
|
||||||
|
throw new FileNotFoundException($"'{manifestPath}' doesn't exist.");
|
||||||
|
|
||||||
|
XmlDocument manifestDoc = new XmlDocument();
|
||||||
|
manifestDoc.Load(manifestPath);
|
||||||
|
|
||||||
|
InjectAndroidManifest(manifestPath, manifestDoc);
|
||||||
|
|
||||||
|
manifestDoc.Save(manifestPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void InjectAndroidManifest(string manifestPath, XmlDocument manifestDoc)
|
||||||
|
{
|
||||||
|
string mainActivity = GetLauncherActivity(manifestDoc);
|
||||||
|
|
||||||
|
AppendAndroidMetadataField(manifestPath, manifestDoc, K_CUSTOM_NOTIFICATION_ACTIVITY, mainActivity);
|
||||||
|
AppendAndroidPermissionField(manifestPath, manifestDoc, K_PREMISSION_POST_NOTIFICATIONS);
|
||||||
|
|
||||||
|
UnityEngine.Debug.Log($"<color=#88ff00>Add custom notification activity: {mainActivity} success!!</color>");
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void AppendAndroidPermissionField(string manifestPath, XmlDocument xmlDoc, string name, string maxSdk = null)
|
||||||
|
{
|
||||||
|
AppendAndroidPermissionField(manifestPath, xmlDoc, "uses-permission", name, maxSdk);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void AppendAndroidPermissionField(string manifestPath, XmlDocument xmlDoc, string tagName, string name, string maxSdk)
|
||||||
|
{
|
||||||
|
var manifestNode = xmlDoc.SelectSingleNode("manifest");
|
||||||
|
if (manifestNode == null)
|
||||||
|
throw new ArgumentException(string.Format("Missing 'manifest' node in '{0}'.", manifestPath));
|
||||||
|
|
||||||
|
XmlElement metaDataNode = null;
|
||||||
|
foreach (XmlNode node in manifestNode.ChildNodes)
|
||||||
|
{
|
||||||
|
if (!(node is XmlElement) || node.Name != tagName)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var element = (XmlElement)node;
|
||||||
|
var elementName = element.GetAttribute("name", K_ANDROID_NAMESPACE_URI);
|
||||||
|
if (elementName == name)
|
||||||
|
{
|
||||||
|
if (maxSdk == null)
|
||||||
|
return;
|
||||||
|
var maxSdkAttr = element.GetAttribute("maxSdkVersion", K_ANDROID_NAMESPACE_URI);
|
||||||
|
if (!string.IsNullOrEmpty(maxSdkAttr))
|
||||||
|
return;
|
||||||
|
metaDataNode = element;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (metaDataNode == null)
|
||||||
|
{
|
||||||
|
metaDataNode = xmlDoc.CreateElement(tagName);
|
||||||
|
metaDataNode.SetAttribute("name", K_ANDROID_NAMESPACE_URI, name);
|
||||||
|
}
|
||||||
|
if (maxSdk != null)
|
||||||
|
metaDataNode.SetAttribute("maxSdkVersion", K_ANDROID_NAMESPACE_URI, maxSdk);
|
||||||
|
|
||||||
|
manifestNode.AppendChild(metaDataNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void AppendAndroidMetadataField(string manifestPath, XmlDocument xmlDoc, string name, string value)
|
||||||
|
{
|
||||||
|
var applicationNode = xmlDoc.SelectSingleNode("manifest/application");
|
||||||
|
if (applicationNode == null)
|
||||||
|
throw new ArgumentException(string.Format("Missing 'application' node in '{0}'.", manifestPath));
|
||||||
|
|
||||||
|
var nodes = xmlDoc.SelectNodes("manifest/application/meta-data");
|
||||||
|
if (nodes != null)
|
||||||
|
{
|
||||||
|
// Check if there is a 'meta-data' with the same name.
|
||||||
|
foreach (XmlNode node in nodes)
|
||||||
|
{
|
||||||
|
var element = node as XmlElement;
|
||||||
|
if (element == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var elementName = element.GetAttribute("name", K_ANDROID_NAMESPACE_URI);
|
||||||
|
if (elementName == name)
|
||||||
|
{
|
||||||
|
element.SetAttribute("value", K_ANDROID_NAMESPACE_URI, value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
XmlElement metaDataNode = xmlDoc.CreateElement("meta-data");
|
||||||
|
metaDataNode.SetAttribute("name", K_ANDROID_NAMESPACE_URI, name);
|
||||||
|
metaDataNode.SetAttribute("value", K_ANDROID_NAMESPACE_URI, value);
|
||||||
|
|
||||||
|
applicationNode.AppendChild(metaDataNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static string GetLauncherActivity(XmlDocument xmlDoc)
|
||||||
|
{
|
||||||
|
var applicationNode = xmlDoc.SelectSingleNode("manifest/application");
|
||||||
|
if (applicationNode == null)
|
||||||
|
throw new ArgumentException($"Missing 'application' node in doc.");
|
||||||
|
|
||||||
|
var nodes = xmlDoc.SelectNodes("manifest/application/activity");
|
||||||
|
if (nodes != null)
|
||||||
|
{
|
||||||
|
foreach (XmlNode node in nodes)
|
||||||
|
{
|
||||||
|
var activityNode = node as XmlElement;
|
||||||
|
if (activityNode == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (activityNode.HasChildNodes)
|
||||||
|
{
|
||||||
|
var intentFilterNode = activityNode.SelectSingleNode("intent-filter");
|
||||||
|
|
||||||
|
if(intentFilterNode == null || !intentFilterNode.HasChildNodes)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
foreach (XmlElement childNode in intentFilterNode)
|
||||||
|
{
|
||||||
|
if(childNode == null) continue;
|
||||||
|
|
||||||
|
// 判断 action/category 二者取其一
|
||||||
|
if (childNode.Name == "action" && childNode.InnerXml.Contains("android.intent.action.MAIN"))
|
||||||
|
{
|
||||||
|
var activityName = activityNode.GetAttribute("name", K_ANDROID_NAMESPACE_URI);
|
||||||
|
return activityName;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (childNode.Name == "category" && childNode.InnerXml.Contains("android.intent.category.LAUNCHER"))
|
||||||
|
{
|
||||||
|
var activityName = activityNode.GetAttribute("name", K_ANDROID_NAMESPACE_URI);
|
||||||
|
return activityName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return V_DEFAULT_GURU_ACTIVITY;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 2e6de94961cc47abbabbc7e872085a98
|
||||||
|
timeCreated: 1718934648
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"name": "GuruNotification.Editor",
|
||||||
|
"includePlatforms": [
|
||||||
|
"Editor"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: e75025463d0c436482bf4c3dab674315
|
||||||
|
timeCreated: 1718845553
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: d6dd827f370441718ca2e49f3f603e4e
|
||||||
|
timeCreated: 1718845525
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
namespace Guru.Notification
|
||||||
|
{
|
||||||
|
using System;
|
||||||
|
public interface INotificationAgent
|
||||||
|
{
|
||||||
|
void Init();
|
||||||
|
|
||||||
|
string GetStatus();
|
||||||
|
|
||||||
|
bool IsAllowed();
|
||||||
|
|
||||||
|
void RequestPermission(Action<string> callback = null);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 43e051a65e9b469b8b9e8a9f6b4be944
|
||||||
|
timeCreated: 1718844775
|
||||||
|
|
@ -0,0 +1,252 @@
|
||||||
|
namespace Guru.Notification
|
||||||
|
{
|
||||||
|
using System;
|
||||||
|
using UnityEngine;
|
||||||
|
#if UNITY_ANDROID
|
||||||
|
using UnityEngine.Android;
|
||||||
|
using Unity.Notifications.Android;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
public class NotificationAgentAndroid : INotificationAgent
|
||||||
|
{
|
||||||
|
public const string FCM_DEFAULT_CHANNEL_ID = "fcm_default_channel";
|
||||||
|
private const string STATUS_GRANTED = "granted";
|
||||||
|
private const string STATUS_DENIDED = "denied";
|
||||||
|
// private const string STATUS_NOT_DETERMINED = "not_determined";
|
||||||
|
private const int REQUEST_PERMISSION_SDK_VERSION = 33;
|
||||||
|
private const string PERMISSION_POST_NOTIFICATION = "android.permission.POST_NOTIFICATIONS";
|
||||||
|
|
||||||
|
private bool _initOnce = false;
|
||||||
|
private string _notiStatus;
|
||||||
|
|
||||||
|
private string SavedNotiPermStatus
|
||||||
|
{
|
||||||
|
get => PlayerPrefs.GetString(nameof(SavedNotiPermStatus), "");
|
||||||
|
set => PlayerPrefs.SetString(nameof(SavedNotiPermStatus), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 初始化
|
||||||
|
/// </summary>
|
||||||
|
public void Init()
|
||||||
|
{
|
||||||
|
if (!_initOnce) return;
|
||||||
|
_initOnce = true;
|
||||||
|
|
||||||
|
_notiStatus = STATUS_DENIDED;
|
||||||
|
if (!string.IsNullOrEmpty(SavedNotiPermStatus))
|
||||||
|
{
|
||||||
|
_notiStatus = SavedNotiPermStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if UNITY_ANDROID
|
||||||
|
InitPlugins();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取状态
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public string GetStatus()
|
||||||
|
{
|
||||||
|
if (!_initOnce) Init();
|
||||||
|
#if UNITY_ANDROID
|
||||||
|
UpdateNotiStatus();
|
||||||
|
#endif
|
||||||
|
return _notiStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 设置授权状态
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="status">授权状态</param>
|
||||||
|
private void SetGrantStatus(string status)
|
||||||
|
{
|
||||||
|
_notiStatus = status;
|
||||||
|
SavedNotiPermStatus = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public bool IsAllowed()
|
||||||
|
{
|
||||||
|
return _notiStatus == STATUS_GRANTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RequestPermission(Action<string> callback = null)
|
||||||
|
{
|
||||||
|
#if UNITY_ANDROID
|
||||||
|
RequestAndroidPermission(callback);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------- Android 获取状态逻辑 --------------------
|
||||||
|
|
||||||
|
#if UNITY_ANDROID
|
||||||
|
|
||||||
|
private PermissionStatus _permissionStatus;
|
||||||
|
|
||||||
|
private void TryExecute(Action handler)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
handler?.Invoke();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Debug.LogError(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 初始化插件
|
||||||
|
/// </summary>
|
||||||
|
private void InitPlugins()
|
||||||
|
{
|
||||||
|
AndroidNotificationCenter.Initialize();
|
||||||
|
Debug.Log($"[Noti][AND] --- Notification Service InitPlugins");
|
||||||
|
|
||||||
|
UpdateNotiStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 更新 Notification 状态码
|
||||||
|
/// </summary>
|
||||||
|
private void UpdateNotiStatus()
|
||||||
|
{
|
||||||
|
|
||||||
|
TryExecute(() =>
|
||||||
|
{
|
||||||
|
_permissionStatus = AndroidNotificationCenter.UserPermissionToPost;
|
||||||
|
var status = "";
|
||||||
|
switch (_permissionStatus)
|
||||||
|
{
|
||||||
|
// case PermissionStatus.NotRequested:
|
||||||
|
// _notiStatus = STATUS_NOT_DETERMINED;
|
||||||
|
// break;
|
||||||
|
case PermissionStatus.Allowed:
|
||||||
|
status = STATUS_GRANTED;;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
status = STATUS_DENIDED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
SetGrantStatus(status);
|
||||||
|
Debug.LogWarning($"[SDK][AND] --- UpdateNotiStatus:{_notiStatus} | UserPermissionToPost:{_permissionStatus}");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private Action<string> _onPermissionCallback;
|
||||||
|
private PermissionCallbacks _permissionCallbacks;
|
||||||
|
private void RequestAndroidPermission(Action<string> callback = null)
|
||||||
|
{
|
||||||
|
UpdateNotiStatus();
|
||||||
|
|
||||||
|
if (_notiStatus == STATUS_GRANTED)
|
||||||
|
{
|
||||||
|
callback?.Invoke(_notiStatus);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_onPermissionCallback = callback;
|
||||||
|
TryExecute(() =>
|
||||||
|
{
|
||||||
|
var sdkInt = GetAndroidSDKVersion();
|
||||||
|
if (sdkInt < REQUEST_PERMISSION_SDK_VERSION)
|
||||||
|
{
|
||||||
|
// 低版本处理方式
|
||||||
|
Debug.Log($"[SDK][Noti] --- #2 SDK {sdkInt} not requested -> open channel");
|
||||||
|
AndroidNotificationCenter.RegisterNotificationChannel(new AndroidNotificationChannel(FCM_DEFAULT_CHANNEL_ID,
|
||||||
|
FCM_DEFAULT_CHANNEL_ID, "", Importance.Default)); // 打开ChannelID
|
||||||
|
SetGrantStatus(STATUS_GRANTED);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// SDK 33 以上,请求弹窗
|
||||||
|
bool hasPermission = Permission.HasUserAuthorizedPermission(PERMISSION_POST_NOTIFICATION);
|
||||||
|
if (hasPermission)
|
||||||
|
{
|
||||||
|
SetGrantStatus(STATUS_GRANTED);
|
||||||
|
callback?.Invoke(STATUS_GRANTED);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Debug.Log($"[SDK][Noti] --- #3 SDK {sdkInt} :: Ask Post Permission");
|
||||||
|
Permission.RequestUserPermission(PERMISSION_POST_NOTIFICATION, SetupPermissionCallbacks());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private PermissionCallbacks SetupPermissionCallbacks()
|
||||||
|
{
|
||||||
|
if(_permissionCallbacks != null) DisposePermissionCallbacks();
|
||||||
|
_permissionCallbacks = new PermissionCallbacks();
|
||||||
|
_permissionCallbacks.PermissionGranted += OnPermissionGranted;
|
||||||
|
_permissionCallbacks.PermissionDenied += OnPermissionDenied;
|
||||||
|
_permissionCallbacks.PermissionDeniedAndDontAskAgain += OnPermissionDenied;
|
||||||
|
return _permissionCallbacks;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DisposePermissionCallbacks()
|
||||||
|
{
|
||||||
|
if (_permissionCallbacks != null)
|
||||||
|
{
|
||||||
|
_permissionCallbacks.PermissionGranted -= OnPermissionGranted;
|
||||||
|
_permissionCallbacks.PermissionDenied -= OnPermissionDenied;
|
||||||
|
_permissionCallbacks.PermissionDeniedAndDontAskAgain -= OnPermissionDenied;
|
||||||
|
_permissionCallbacks = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 请求通过
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="permissionName"></param>
|
||||||
|
private void OnPermissionGranted(string permissionName)
|
||||||
|
{
|
||||||
|
if (permissionName == PERMISSION_POST_NOTIFICATION)
|
||||||
|
{
|
||||||
|
_notiStatus = STATUS_GRANTED;
|
||||||
|
_onPermissionCallback?.Invoke(_notiStatus);
|
||||||
|
}
|
||||||
|
SetGrantStatus(STATUS_GRANTED);
|
||||||
|
DisposePermissionCallbacks();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 请求拒绝
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="permissionName"></param>
|
||||||
|
private void OnPermissionDenied(string permissionName)
|
||||||
|
{
|
||||||
|
if (permissionName == PERMISSION_POST_NOTIFICATION)
|
||||||
|
{
|
||||||
|
_notiStatus = STATUS_DENIDED;
|
||||||
|
_onPermissionCallback?.Invoke(_notiStatus);
|
||||||
|
}
|
||||||
|
SetGrantStatus(STATUS_DENIDED);
|
||||||
|
DisposePermissionCallbacks();
|
||||||
|
}
|
||||||
|
|
||||||
|
private int GetAndroidSDKVersion()
|
||||||
|
{
|
||||||
|
int sdkInt = 999;
|
||||||
|
TryExecute(() =>
|
||||||
|
{
|
||||||
|
using (AndroidJavaClass jc = new AndroidJavaClass("android.os.Build$VERSION"))
|
||||||
|
{
|
||||||
|
sdkInt = jc.GetStatic<int>("SDK_INT");
|
||||||
|
Debug.LogWarning($"[SDK] --- Android SDK Version:{sdkInt}");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return sdkInt;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 554fcea56ce74a80a2424e5c037ce6c0
|
||||||
|
timeCreated: 1718844764
|
||||||
|
|
@ -0,0 +1,151 @@
|
||||||
|
|
||||||
|
|
||||||
|
namespace Guru.Notification
|
||||||
|
{
|
||||||
|
using System;
|
||||||
|
using UnityEngine;
|
||||||
|
#if UNITY_IOS
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Unity.Notifications.iOS;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
public class NotificationAgentIOS : INotificationAgent
|
||||||
|
{
|
||||||
|
|
||||||
|
private const string STATUS_GRANTED = "granted";
|
||||||
|
private const string STATUS_DENIDED = "denied";
|
||||||
|
private const string STATUS_PROVISIONAL = "provisional";
|
||||||
|
private const string STATUS_NOT_DETERMINED = "not_determined";
|
||||||
|
|
||||||
|
private static bool _initOnce;
|
||||||
|
private static int _waitSeconds = 30;
|
||||||
|
private string SavedNotiPermStatus
|
||||||
|
{
|
||||||
|
get => PlayerPrefs.GetString(nameof(SavedNotiPermStatus), "");
|
||||||
|
set => PlayerPrefs.SetString(nameof(SavedNotiPermStatus), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private string _notiStatus;
|
||||||
|
|
||||||
|
public void Init()
|
||||||
|
{
|
||||||
|
if (_initOnce) return;
|
||||||
|
_initOnce = true;
|
||||||
|
|
||||||
|
_notiStatus = SavedNotiPermStatus;
|
||||||
|
if (string.IsNullOrEmpty(_notiStatus))
|
||||||
|
_notiStatus = STATUS_NOT_DETERMINED;
|
||||||
|
|
||||||
|
#if UNITY_IOS
|
||||||
|
InitPlugins();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetStatus()
|
||||||
|
{
|
||||||
|
if (!_initOnce) Init();
|
||||||
|
#if UNITY_IOS
|
||||||
|
UpdateStatus();
|
||||||
|
#endif
|
||||||
|
return _notiStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsAllowed()
|
||||||
|
{
|
||||||
|
return _notiStatus == STATUS_GRANTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RequestPermission(Action<string> callback = null)
|
||||||
|
{
|
||||||
|
if (!_initOnce) Init();
|
||||||
|
|
||||||
|
if (_notiStatus == STATUS_GRANTED || _notiStatus == STATUS_DENIDED)
|
||||||
|
{
|
||||||
|
Debug.Log($"[SDK][Noti][iOS] --- Already has Status: {_notiStatus}");
|
||||||
|
callback?.Invoke(_notiStatus); // 已获得授权, 直接返回结果
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if UNITY_IOS
|
||||||
|
RequestIOSPermission(callback);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if UNITY_IOS
|
||||||
|
|
||||||
|
private void InitPlugins()
|
||||||
|
{
|
||||||
|
UpdateStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 更新状态
|
||||||
|
/// </summary>
|
||||||
|
private void UpdateStatus()
|
||||||
|
{
|
||||||
|
string status = STATUS_NOT_DETERMINED;
|
||||||
|
var authorizationStatus = iOSNotificationCenter.GetNotificationSettings().AuthorizationStatus;
|
||||||
|
switch (authorizationStatus)
|
||||||
|
{
|
||||||
|
case AuthorizationStatus.Authorized:
|
||||||
|
status = STATUS_GRANTED;
|
||||||
|
break;
|
||||||
|
case AuthorizationStatus.Denied:
|
||||||
|
status = STATUS_DENIDED;
|
||||||
|
break;
|
||||||
|
case AuthorizationStatus.NotDetermined:
|
||||||
|
status = STATUS_NOT_DETERMINED;
|
||||||
|
break;
|
||||||
|
case AuthorizationStatus.Provisional:
|
||||||
|
status = STATUS_PROVISIONAL;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Debug.Log($"[SDK][Noti][iOS] --- Unmarked AuthorizationStatus: {status}");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
SetGrantStatus(status);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetGrantStatus(string status)
|
||||||
|
{
|
||||||
|
_notiStatus = status;
|
||||||
|
SavedNotiPermStatus = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 请求 IOS 的推送
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="callback"></param>
|
||||||
|
private async void RequestIOSPermission(Action<string> callback = null)
|
||||||
|
{
|
||||||
|
Debug.Log($"[SDK][Noti][iOS] --- RequestIOSPermission start");
|
||||||
|
int timePassed = 0;
|
||||||
|
using (var req = new AuthorizationRequest(AuthorizationOption.Alert | AuthorizationOption.Badge, true))
|
||||||
|
{
|
||||||
|
while (!req.IsFinished && timePassed < _waitSeconds)
|
||||||
|
{
|
||||||
|
timePassed++;
|
||||||
|
await Task.Delay(1000);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (timePassed >= _waitSeconds)
|
||||||
|
{
|
||||||
|
Debug.LogWarning($"[SDK][Noti][iOS] --- RequestIOSPermission timeout");
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateStatus();
|
||||||
|
callback?.Invoke(_notiStatus);
|
||||||
|
Debug.Log($"[SDK][Noti][iOS] --- User Selected: {_notiStatus}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 5068c6e238e74251955320761c96182b
|
||||||
|
timeCreated: 1718871877
|
||||||
|
|
@ -0,0 +1,58 @@
|
||||||
|
|
||||||
|
|
||||||
|
namespace Guru.Notification
|
||||||
|
{
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// For Editor to use Notifications
|
||||||
|
/// </summary>
|
||||||
|
public class NotificationAgentStub: INotificationAgent
|
||||||
|
{
|
||||||
|
private const string STATUS_GRANTED = "granted";
|
||||||
|
private const string STATUS_DENIDED = "denied";
|
||||||
|
private const string STATUS_NOT_DETERMINED = "not_determined";
|
||||||
|
|
||||||
|
private Action<string> _onPermissionCallback;
|
||||||
|
private float _delaySeconds = 1.0f;
|
||||||
|
|
||||||
|
private string EditorGrantedStatus
|
||||||
|
{
|
||||||
|
get => PlayerPrefs.GetString(nameof(EditorGrantedStatus), STATUS_NOT_DETERMINED);
|
||||||
|
set => PlayerPrefs.SetString(nameof(EditorGrantedStatus), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Init()
|
||||||
|
{
|
||||||
|
Debug.Log($"[SDK][Noti][EDT] --- NotificationAgentStub Init: {EditorGrantedStatus}");
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetStatus() => EditorGrantedStatus;
|
||||||
|
|
||||||
|
public bool IsAllowed()
|
||||||
|
{
|
||||||
|
return EditorGrantedStatus == STATUS_GRANTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RequestPermission(Action<string> callback = null)
|
||||||
|
{
|
||||||
|
Debug.Log($"[SDK][Noti][EDT] --- RequestPermission ---");
|
||||||
|
_onPermissionCallback = callback;
|
||||||
|
DelayCallPermissionHandle();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 延迟模拟回调
|
||||||
|
/// </summary>
|
||||||
|
private async void DelayCallPermissionHandle()
|
||||||
|
{
|
||||||
|
await Task.Delay((int)(1000 * _delaySeconds));
|
||||||
|
EditorGrantedStatus = STATUS_GRANTED;
|
||||||
|
_onPermissionCallback?.Invoke(EditorGrantedStatus);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 6550e85d25634c46b7a57c490dcea173
|
||||||
|
timeCreated: 1718850440
|
||||||
|
|
@ -0,0 +1,112 @@
|
||||||
|
namespace Guru.Notification
|
||||||
|
{
|
||||||
|
using UnityEngine;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 消息管理器
|
||||||
|
/// </summary>
|
||||||
|
public class NotificationService
|
||||||
|
{
|
||||||
|
// 服务版本号
|
||||||
|
public const string Version = "0.0.1";
|
||||||
|
|
||||||
|
|
||||||
|
// 初始化标志位
|
||||||
|
private static bool _initOnce;
|
||||||
|
|
||||||
|
private static string DefaultPermissionStatus
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
#if UNITY_IOS
|
||||||
|
return "not_determined";
|
||||||
|
#endif
|
||||||
|
return "denied";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#region 初始化
|
||||||
|
|
||||||
|
private static INotificationAgent _agent;
|
||||||
|
|
||||||
|
internal static INotificationAgent Agent
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_agent == null)
|
||||||
|
{
|
||||||
|
_agent = GetAgent();
|
||||||
|
}
|
||||||
|
return _agent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static INotificationAgent GetAgent()
|
||||||
|
{
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
return new NotificationAgentStub();
|
||||||
|
#elif UNITY_ANDROID
|
||||||
|
return new NotificationAgentAndroid();
|
||||||
|
#elif UNITY_IOS
|
||||||
|
return new NotificationAgentIOS();
|
||||||
|
#endif
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 初始化
|
||||||
|
/// </summary>
|
||||||
|
public static void Initialize()
|
||||||
|
{
|
||||||
|
if (_initOnce) return;
|
||||||
|
_initOnce = true;
|
||||||
|
Agent?.Init(); // 初始化代理
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#region 接口
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 拉起 Noti 请求
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="callback"></param>
|
||||||
|
public static void RequestPermission(Action<string> callback = null)
|
||||||
|
{
|
||||||
|
if (Agent != null)
|
||||||
|
{
|
||||||
|
Agent.RequestPermission(callback);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Debug.LogError($"[SDK][Noti] --- Agent is missing, return default status: {DefaultPermissionStatus}");
|
||||||
|
callback?.Invoke(DefaultPermissionStatus);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsPermissionGranted()
|
||||||
|
{
|
||||||
|
return Agent?.IsAllowed() ?? false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetStatus()
|
||||||
|
{
|
||||||
|
if(!_initOnce) Initialize();
|
||||||
|
|
||||||
|
if(Agent != null) return Agent.GetStatus();
|
||||||
|
|
||||||
|
Debug.LogError($"[SDK][Noti] --- Agent is missing, return default status: {DefaultPermissionStatus}");
|
||||||
|
return DefaultPermissionStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: e0f31750e8bc48a6a5e4f56ee2d5e1cc
|
||||||
|
timeCreated: 1718846076
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
namespace Guru
|
namespace Guru
|
||||||
{
|
{
|
||||||
using System;
|
using System;
|
||||||
|
using UnityEngine;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
public abstract class RemoteConfigBase<T>: IRemoteConfig<T> where T : IRemoteConfig<T>
|
public abstract class RemoteConfigBase<T>: IRemoteConfig<T> where T : IRemoteConfig<T>
|
||||||
{
|
{
|
||||||
|
|
@ -8,6 +10,8 @@ namespace Guru
|
||||||
/// 配置是否可用
|
/// 配置是否可用
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool enable { get; set; } = true;
|
public bool enable { get; set; } = true;
|
||||||
|
|
||||||
|
[JsonIgnore]
|
||||||
public Action<T> OnValueChanged { get; set; }
|
public Action<T> OnValueChanged { get; set; }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 转为Json
|
/// 转为Json
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"com.unity.ads.ios-support": "1.2.0",
|
"com.unity.ads.ios-support": "1.2.0",
|
||||||
"com.unity.editorcoroutines": "1.0.0",
|
"com.unity.editorcoroutines": "1.0.0",
|
||||||
|
"com.unity.mobile.notifications": "2.2.2",
|
||||||
"com.unity.mobile.android-logcat": "1.3.2",
|
"com.unity.mobile.android-logcat": "1.3.2",
|
||||||
"com.unity.purchasing": "4.10.0"
|
"com.unity.purchasing": "4.10.0"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue