release: 1.4.2

This commit is contained in:
2026-03-18 17:16:40 +08:00
parent da3d20be8c
commit 4024c15f5c
10 changed files with 328 additions and 6 deletions

View File

@@ -19,6 +19,18 @@ namespace AnyThink.Scripts.IntegrationManager.Editor
public static string PLUGIN_VERSION = "2.1.7";
public static bool isDebug = false;
public static bool EnableEditorTools
{
get
{
#if AnyThinkSDKEditor
return true;
#else
return false;
#endif
}
}
public static int PLUGIN_TYPE = 1;
public static int OS_ANDROID = 1;
public static int OS_IOS = 2;

View File

@@ -42,6 +42,12 @@ namespace AnyThink.Scripts.IntegrationManager.Editor
public IEnumerator loadPluginData(Action<PluginData> callback)
{
if (!ATConfig.EnableEditorTools)
{
callback?.Invoke(null);
yield break;
}
var anythinkVersionRequest = UnityWebRequest.Get(ATNetInfo.getPluginConfigUrl(ATConfig.PLUGIN_VERSION));
var webRequest = anythinkVersionRequest.SendWebRequest();
while (!webRequest.isDone)
@@ -74,6 +80,11 @@ namespace AnyThink.Scripts.IntegrationManager.Editor
public IEnumerator loadNetworksData(PluginData pluginData, Action<PluginData> callback)
{
if (!ATConfig.EnableEditorTools)
{
callback?.Invoke(pluginData);
yield break;
}
Network network = pluginData.anyThink;
if (pluginData == null)
@@ -125,11 +136,22 @@ namespace AnyThink.Scripts.IntegrationManager.Editor
/// <returns></returns>
public void downloadPlugin(Network network, int os =1, bool showImport = false)
{
if (!ATConfig.EnableEditorTools)
{
ATLog.log("downloadPlugin() >>> AnyThinkSDKEditor disabled, skip remote download.");
return;
}
ATEditorCoroutine.startCoroutine(downloadPluginWithEnumerator(network, os, showImport));
}
public IEnumerator downloadPluginWithEnumerator(Network network, int os, bool showImport)
{
if (!ATConfig.EnableEditorTools)
{
yield break;
}
ATLog.log("downloadPluginWithEnumerator() >>> networkName: " + network.Name + " os: " + os);
// if (downloadPluginRequest != null)
// {
@@ -190,6 +212,12 @@ namespace AnyThink.Scripts.IntegrationManager.Editor
//默认下载core包在下载完network的数据时。
public void downloadCorePlugin(PluginData pluginData)
{
if (!ATConfig.EnableEditorTools)
{
ATLog.log("downloadCorePlugin() >>> AnyThinkSDKEditor disabled, skip remote download.");
return;
}
mPluginData = pluginData;
var requestParams = pluginData.requestParams;
var pluginSettingData = pluginData.pluginSettingData;
@@ -278,6 +306,12 @@ namespace AnyThink.Scripts.IntegrationManager.Editor
public void networkInstallOrUpdate(PluginData pluginData, Network network, int os)
{
if (!ATConfig.EnableEditorTools)
{
ATLog.log("networkInstallOrUpdate() >>> AnyThinkSDKEditor disabled, skip remote download.");
return;
}
downloadPlugin(network, os);
}

View File

@@ -61,6 +61,11 @@ namespace AnyThink.Scripts.IntegrationManager.Editor
public static void ShowManager()
{
if (!ATConfig.EnableEditorTools)
{
return;
}
var manager = GetWindow<ATIntegrationManagerWindow>(utility: true, title: windowTitle, focus: true);
manager.minSize = windowMinSize;
// manager.maxSize = windowMinSize;
@@ -125,6 +130,11 @@ namespace AnyThink.Scripts.IntegrationManager.Editor
warningIcon = new Texture2D(100, 100, TextureFormat.RGBA32, false);
warningIcon.LoadImage(warningIconData);
if (!ATConfig.EnableEditorTools)
{
return;
}
loadPluginData();
//热更新
ATIntegrationHotFix.Instance.loadHotFixData();
@@ -158,6 +168,13 @@ namespace AnyThink.Scripts.IntegrationManager.Editor
private void OnGUI()
{
if (!ATConfig.EnableEditorTools)
{
GUILayout.Space(10);
EditorGUILayout.HelpBox("AnyThinkSDKEditor 未开启SDK Manager 已禁用。需要维护 SDK 时请先添加 Scripting Define Symbol: AnyThinkSDKEditor。", MessageType.Info);
return;
}
// OnGUI is called on each frame draw, so we don't want to do any unnecessary calculation if we can avoid it. So only calculate it when the width actually changed.
if (Math.Abs(previousWindowWidth - position.width) > 1)
{
@@ -242,6 +259,13 @@ namespace AnyThink.Scripts.IntegrationManager.Editor
//获取插件和SDK的版本数据
private void loadPluginData()
{
if (!ATConfig.EnableEditorTools)
{
pluginData = null;
pluginDataLoadFailed = false;
return;
}
if (loadDataCoroutine != null)
{
loadDataCoroutine.Stop();
@@ -275,6 +299,11 @@ namespace AnyThink.Scripts.IntegrationManager.Editor
//获取networks
private void loadNetworksData(PluginData pluginData)
{
if (!ATConfig.EnableEditorTools)
{
return;
}
ATEditorCoroutine.startCoroutine(ATIntegrationManager.Instance.loadNetworksData(pluginData, data =>
{
pluginData = data;

View File

@@ -26,12 +26,23 @@ namespace AnyThink.Scripts.IntegrationManager.Editor
public void loadHotFixData()
{
if (!ATConfig.EnableEditorTools)
{
ATLog.log("loadHotFixData() >>> AnyThinkSDKEditor disabled, skip hotfix check.");
return;
}
var downloadUrl = ATNetInfo.getHotfixPluginDownloadUrl(ATConfig.PLUGIN_VERSION);
ATLog.log("loadHotFixData() >>> downloadUrl: " + downloadUrl);
ATEditorCoroutine.startCoroutine(loadHotFixDataWithIEnumerator(downloadUrl));
}
private IEnumerator loadHotFixDataWithIEnumerator(string url) {
if (!ATConfig.EnableEditorTools)
{
yield break;
}
var hotFixDataRequest = UnityWebRequest.Get(url);
var webRequest = hotFixDataRequest.SendWebRequest();
while (!webRequest.isDone)
@@ -86,6 +97,11 @@ namespace AnyThink.Scripts.IntegrationManager.Editor
}
private IEnumerator loadHotFixPlugin(HotfixPluginData hotFixDataObj) {
if (!ATConfig.EnableEditorTools)
{
yield break;
}
var path = Path.Combine(Application.temporaryCachePath, hotFixDataObj.file_name);
ATLog.log("downloadPluginWithEnumerator() >>> path: " + path);
#if UNITY_2017_2_OR_NEWER

View File

@@ -7,6 +7,7 @@ namespace AnyThink.Scripts.IntegrationManager.Editor
{
public class AnyThinkMenuItems : MonoBehaviour
{
#if AnyThinkSDKEditor
/**
* The special characters at the end represent a shortcut for this action.
*
@@ -33,5 +34,6 @@ namespace AnyThink.Scripts.IntegrationManager.Editor
// }
Application.OpenURL("https://newdocs.toponad.com/docs/lgfbO4");
}
#endif
}
}

View File

@@ -21,9 +21,16 @@ public class ADListenerAggregator
client.onAdClickEvent += this.onRewardedVideoAdPlayClicked;
client.onAdLoadEvent += this.onRewardedVideoAdLoaded;
client.onAdLoadFailureEvent += this.onRewardedVideoAdLoadFail;
client.onAdVideoStartEvent += this.onRewardedVideoAdPlayStart;
client.onAdVideoEndEvent += this.onRewardedVideoAdPlayEnd;
client.onAdVideoCloseEvent += this.onRewardedVideoAdPlayClosed;
client.onAdVideoFailureEvent += this.onRewardedVideoAdPlayFail;
client.onAdSourceAttemptEvent += this.startLoadingRewardedAdSource;
client.onAdSourceFilledEvent += this.finishLoadingRewardedAdSource;
client.onAdSourceLoadFailureEvent += this.failToLoadRewardedAdSource;
client.onAdSourceBiddingAttemptEvent += this.startBiddingRewardedAdSource;
client.onAdSourceBiddingFilledEvent += this.finishBiddingRewardedAdSource;
client.onAdSourceBiddingFailureEvent += this.failBiddingRewardedAdSource;
}
this._awardVideoListener = listener;
@@ -62,6 +69,15 @@ public class ADListenerAggregator
}
/***
* The Ad play start (note: for Android, all callback methods are not in the main thread of Unity)
*/
void onRewardedVideoAdPlayStart(object sender, ATAdEventArgs callbackInfo)
{
ToponUnityThread.Post(() => this._awardVideoListener?.onRewardedVideoAdPlayStart(callbackInfo.placementId,
callbackInfo.callbackInfo));
}
/***
* The Ad play end (note: for Android, all callback methods are not in the main thread of Unity)
*/
@@ -110,6 +126,42 @@ public class ADListenerAggregator
callbackInfo.callbackInfo));
}
void startLoadingRewardedAdSource(object sender, ATAdEventArgs callbackInfo)
{
ToponUnityThread.Post(() => this._awardVideoListener?.startLoadingADSource(callbackInfo.placementId,
callbackInfo.callbackInfo));
}
void finishLoadingRewardedAdSource(object sender, ATAdEventArgs callbackInfo)
{
ToponUnityThread.Post(() => this._awardVideoListener?.finishLoadingADSource(callbackInfo.placementId,
callbackInfo.callbackInfo));
}
void failToLoadRewardedAdSource(object sender, ATAdErrorEventArgs callbackInfo)
{
ToponUnityThread.Post(() => this._awardVideoListener?.failToLoadADSource(callbackInfo.placementId,
callbackInfo.callbackInfo, callbackInfo.errorCode, callbackInfo.errorMessage));
}
void startBiddingRewardedAdSource(object sender, ATAdEventArgs callbackInfo)
{
ToponUnityThread.Post(() => this._awardVideoListener?.startBiddingADSource(callbackInfo.placementId,
callbackInfo.callbackInfo));
}
void finishBiddingRewardedAdSource(object sender, ATAdEventArgs callbackInfo)
{
ToponUnityThread.Post(() => this._awardVideoListener?.finishBiddingADSource(callbackInfo.placementId,
callbackInfo.callbackInfo));
}
void failBiddingRewardedAdSource(object sender, ATAdErrorEventArgs callbackInfo)
{
ToponUnityThread.Post(() => this._awardVideoListener?.failBiddingADSource(callbackInfo.placementId,
callbackInfo.callbackInfo, callbackInfo.errorCode, callbackInfo.errorMessage));
}
/***
* 加载广告成功注意对于Android来说所有回调方法均不在Unity的主线程

View File

@@ -103,6 +103,19 @@ public class ToponAdController : IAdController
return;
}
if (options.InitCustomMap != null && options.InitCustomMap.Count > 0)
{
ATSDKAPI.initCustomMap(options.InitCustomMap);
}
var rewardedPlacementId = _adConfig?.BaseAwardAdKeyValue?.value;
if (!string.IsNullOrWhiteSpace(rewardedPlacementId) &&
options.RewardedCustomData != null &&
options.RewardedCustomData.Count > 0)
{
ATSDKAPI.setCustomDataForPlacementID(options.RewardedCustomData, rewardedPlacementId);
}
if (!string.IsNullOrWhiteSpace(options.Channel))
{
ATSDKAPI.setChannel(options.Channel);

View File

@@ -17,6 +17,8 @@ public sealed class ToponControllerOptions
public const string ExcludeBundleIdsKey = "topon.exclude_bundle_ids";
public const string RewardedExcludeAdSourceIdsKey = "topon.rewarded_exclude_ad_source_ids";
public const string QueryAreaOnInitKey = "topon.query_area_on_init";
public const string InitCustomMapKey = "topon.custom_map";
public const string RewardedCustomDataKey = "topon.rewarded_custom_data";
public string Channel { get; set; }
public string SubChannel { get; set; }
@@ -28,6 +30,8 @@ public sealed class ToponControllerOptions
public string[] ExcludeBundleIds { get; set; }
public string[] RewardedExcludeAdSourceIds { get; set; }
public bool QueryAreaOnInit { get; set; }
public Dictionary<string, string> InitCustomMap { get; set; }
public Dictionary<string, string> RewardedCustomData { get; set; }
public Action<string> OnAreaReceived { get; set; }
public Action<string> OnAreaError { get; set; }
@@ -87,6 +91,8 @@ public sealed class ToponControllerOptions
ExcludeBundleIds = GetStringArray(map, ExcludeBundleIdsKey) ?? ExcludeBundleIds;
RewardedExcludeAdSourceIds = GetStringArray(map, RewardedExcludeAdSourceIdsKey) ?? RewardedExcludeAdSourceIds;
QueryAreaOnInit = GetBool(map, QueryAreaOnInitKey) ?? QueryAreaOnInit;
InitCustomMap = MergeMaps(InitCustomMap, GetPrefixedMap(map, InitCustomMapKey + "."));
RewardedCustomData = MergeMaps(RewardedCustomData, GetPrefixedMap(map, RewardedCustomDataKey + "."));
}
private void ApplyLegacyArgs(object[] args)
@@ -124,6 +130,8 @@ public sealed class ToponControllerOptions
ExcludeBundleIds = explicitOptions.ExcludeBundleIds ?? ExcludeBundleIds;
RewardedExcludeAdSourceIds = explicitOptions.RewardedExcludeAdSourceIds ?? RewardedExcludeAdSourceIds;
QueryAreaOnInit = explicitOptions.QueryAreaOnInit || QueryAreaOnInit;
InitCustomMap = MergeMaps(InitCustomMap, explicitOptions.InitCustomMap);
RewardedCustomData = MergeMaps(RewardedCustomData, explicitOptions.RewardedCustomData);
OnAreaReceived = explicitOptions.OnAreaReceived ?? OnAreaReceived;
OnAreaError = explicitOptions.OnAreaError ?? OnAreaError;
}
@@ -143,7 +151,23 @@ public sealed class ToponControllerOptions
continue;
}
map[entry.Key.ToString()] = ConvertDictionaryValue(entry.Value);
var key = entry.Key.ToString();
if (entry.Value is IDictionary nestedDictionary)
{
if (string.Equals(key, InitCustomMapKey, StringComparison.OrdinalIgnoreCase))
{
InitCustomMap = MergeMaps(InitCustomMap, ToStringMap(nestedDictionary));
continue;
}
if (string.Equals(key, RewardedCustomDataKey, StringComparison.OrdinalIgnoreCase))
{
RewardedCustomData = MergeMaps(RewardedCustomData, ToStringMap(nestedDictionary));
continue;
}
}
map[key] = ConvertDictionaryValue(entry.Value);
}
Channel = GetString(map, ChannelKey, "channel") ?? Channel;
@@ -156,6 +180,8 @@ public sealed class ToponControllerOptions
ExcludeBundleIds = GetStringArray(map, ExcludeBundleIdsKey) ?? ExcludeBundleIds;
RewardedExcludeAdSourceIds = GetStringArray(map, RewardedExcludeAdSourceIdsKey) ?? RewardedExcludeAdSourceIds;
QueryAreaOnInit = GetBool(map, QueryAreaOnInitKey) ?? QueryAreaOnInit;
InitCustomMap = MergeMaps(InitCustomMap, GetPrefixedMap(map, InitCustomMapKey + "."));
RewardedCustomData = MergeMaps(RewardedCustomData, GetPrefixedMap(map, RewardedCustomDataKey + "."));
}
private static string GetString(IDictionary<string, string> map, params string[] keys)
@@ -225,6 +251,54 @@ public sealed class ToponControllerOptions
return items.Length > 0 ? items : null;
}
private static Dictionary<string, string> GetPrefixedMap(IDictionary<string, string> map, string prefix)
{
var result = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
foreach (var pair in map)
{
if (!pair.Key.StartsWith(prefix, StringComparison.OrdinalIgnoreCase))
{
continue;
}
var nestedKey = pair.Key.Substring(prefix.Length).Trim();
if (string.IsNullOrWhiteSpace(nestedKey) || string.IsNullOrWhiteSpace(pair.Value))
{
continue;
}
result[nestedKey] = pair.Value.Trim();
}
return result.Count > 0 ? result : null;
}
private static Dictionary<string, string> MergeMaps(
Dictionary<string, string> current,
Dictionary<string, string> incoming)
{
if (incoming == null || incoming.Count == 0)
{
return current;
}
var result = current != null
? new Dictionary<string, string>(current, StringComparer.OrdinalIgnoreCase)
: new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
foreach (var pair in incoming)
{
if (string.IsNullOrWhiteSpace(pair.Key) || string.IsNullOrWhiteSpace(pair.Value))
{
continue;
}
result[pair.Key] = pair.Value;
}
return result.Count > 0 ? result : null;
}
private static bool TryConvertBool(object value, out bool result)
{
switch (value)
@@ -287,4 +361,27 @@ public sealed class ToponControllerOptions
return value.ToString();
}
private static Dictionary<string, string> ToStringMap(IDictionary dictionary)
{
var result = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
foreach (DictionaryEntry entry in dictionary)
{
if (entry.Key == null || entry.Value == null)
{
continue;
}
var key = entry.Key.ToString()?.Trim();
var value = entry.Value.ToString()?.Trim();
if (string.IsNullOrWhiteSpace(key) || string.IsNullOrWhiteSpace(value))
{
continue;
}
result[key] = value;
}
return result.Count > 0 ? result : null;
}
}

View File

@@ -2,7 +2,7 @@
"name": "com.commercialization.topon",
"displayName": "Commercialization.topon",
"description": "基于topon的广告sdk封装依赖基础商业化模块",
"version": "1.4.1",
"version": "1.4.2",
"unity": "2021.1",
"license": "MIT",
"repository": {

View File

@@ -185,9 +185,77 @@ EDM4U 依赖解析器,负责消费 `Dependencies.xml` 并拉取 Android/iOS
- `AwardVideoPlayer` 必须通过 `ADListenerAggregator.BindAwardVideoListener(...)` 绑定。
- `InteractionPlayer` 必须通过 `ADListenerAggregator.BindInterstitialAdListener(...)` 绑定。
- 奖励视频链路的旧 listener 回调必须继续完整桥接到 Unity 主线程,不能直接在 SDK 子线程里触发业务逻辑。
如果升级后官方再次调整回调模型,优先延续这层桥接,不要直接把抽象层改成强耦合官方回调。
### 5.4 `ToponAdController` 配置入口规范
`ToponAdController` 现在支持两类初始化输入:
1. 兼容旧参数:
- `args[0]``channel`
- `args[1]``debug`
2. 推荐新参数:
- 通过 `ADConfig.CommonKeyValues`
- 或额外传入 `ToponControllerOptions`
- 或额外传入 `IDictionary`
当前已支持的配置 key
- `topon.channel`
- `topon.sub_channel`
- `topon.debug`
- `topon.debugger_key`
- `topon.sdk_area`
- `topon.longitude`
- `topon.latitude`
- `topon.exclude_bundle_ids`
- `topon.rewarded_exclude_ad_source_ids`
- `topon.query_area_on_init`
- `topon.custom_map.<name>`
- `topon.rewarded_custom_data.<name>`
说明:
- `topon.exclude_bundle_ids`
- 用于全局排除指定广告主 bundle id
- `topon.rewarded_exclude_ad_source_ids`
- 用于当前激励视频广告位排除指定广告源
- `topon.query_area_on_init`
- 初始化后主动查询 SDK 当前区域
- 结果会回写到 `ToponAdController.LastDetectedArea`
- `topon.custom_map.<name>`
- 对应 `ATSDKAPI.initCustomMap(...)`
- 注意先设置 custom map再设置 channel/sub_channel
- `topon.rewarded_custom_data.<name>`
- 对应 `ATSDKAPI.setCustomDataForPlacementID(...)`
- 当前默认应用到激励视频广告位
维护约束:
- 当前 IAA 业务主链路以激励视频为主,新功能配置优先围绕 `AwardVideo` 广告位设计。
- 如果后续要补插屏、开屏、原生等广告位的同类配置,优先扩展 `ToponControllerOptions`,不要把 SDK 细节直接散落到业务层。
### 5.5 `AnyThinkSDKEditor` 编辑器开关规范
`AnyThinkPlugin/Script/IntegrationManager/Editor` 这套“SDK Manager / 远端版本检查 / hotfix 检查 / 远端 unitypackage 导入”能力,当前应视为维护工具,而不是业务项目默认能力。
当前约定:
- 只有在定义了 `AnyThinkSDKEditor` 宏时,才允许显示 `AnyThink` 菜单并启用联网检查。
- 未定义 `AnyThinkSDKEditor` 时:
- 不显示 `AnyThink/SDK Manager`
- 不执行 SDK 版本拉取
- 不执行 hotfix 检查
- 不执行远端 unitypackage 下载与导入
这样做的目的:
- 避免业务项目通过包管理接入后,仍然保留官方集成管理器的远端更新入口。
- 降低编辑器侧供应链风险。
- 把 SDK 升级动作收敛到维护工程,而不是下游接入工程。
## 6. Android 构建期自定义规范
Android 的构建后处理分为两层:
@@ -368,4 +436,3 @@ Android 的构建后处理分为两层:
2. 动态路径定位不能回退成固定 `Assets/...` 读取。
3. `Topon_Adapter` 对 core 抽象层的接口契约不能被官方 SDK 反向污染。
4. Android/iOS 构建期补丁必须逐项保留并重新验证。