com.amanotes.gdk 0.2.51 → 0.2.52
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +10 -11
- package/Editor/Extra/GDKCIBuildCommand.cs +312 -0
- package/Editor/Extra/GDKCIBuildCommand.cs.meta +3 -0
- package/Extra/AmaGDKInstaller.unitypackage +0 -0
- package/Extra/CheckDiskSpace.unitypackage +0 -0
- package/Extra/PostProcessor.unitypackage +0 -0
- package/Extra/{AndroidPostProcessor.unitypackage.meta → PostProcessor.unitypackage.meta} +1 -1
- package/Extra/SDKVersionTracking.unitypackage +0 -0
- package/Packages/AmaGDKConfig.unitypackage +0 -0
- package/Packages/AmaGDKExample.unitypackage +0 -0
- package/Packages/AmaGDKTest.unitypackage +0 -0
- package/Packages/AppsFlyerAdapter.unitypackage +0 -0
- package/Packages/FirebaseAnalyticsAdapter.unitypackage +0 -0
- package/Packages/FirebaseRemoteConfigAdapter.unitypackage +0 -0
- package/Packages/IronSourceAdapter.unitypackage +0 -0
- package/Packages/RevenueCatAdapter.unitypackage +0 -0
- package/Runtime/AmaGDK.Analytics.cs +184 -60
- package/Runtime/AmaGDK.cs +1 -1
- package/Runtime/Internal/AmaGDK.Internal.cs +24 -0
- package/Runtime/Internal/AmaGDK.Utils.cs +27 -1
- package/package.json +1 -1
- package/Extra/AndroidPostProcessor.unitypackage +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## [0.2.
|
|
4
|
-
-
|
|
5
|
-
-
|
|
6
|
-
-
|
|
7
|
-
- [
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
-
|
|
13
|
-
- [Core] Init modules before Hooks
|
|
3
|
+
## [0.2.52 - 2024-02-27]
|
|
4
|
+
- Change post processing order
|
|
5
|
+
- Remove GDKInstaller after installed
|
|
6
|
+
- Enable pipeline execution for branches with active merge requests
|
|
7
|
+
- [Fix] Non-fatal exceptions relate to Analytics and Ads
|
|
8
|
+
- Update Google Sheet Id default
|
|
9
|
+
- Optimize GC for Analytics
|
|
10
|
+
|
|
11
|
+
## [0.2.51 - 2024-02-20]
|
|
12
|
+
- Change Google Mobile Ads SDK version , iosPod 10.5.0
|
|
14
13
|
|
|
15
14
|
## [0.2.50 - 2024-02-20]
|
|
16
15
|
- New feature: Modify Android post processor
|
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
using UnityEditor;
|
|
2
|
+
using System.Linq;
|
|
3
|
+
using System;
|
|
4
|
+
using System.IO;
|
|
5
|
+
|
|
6
|
+
namespace Amanotes.Core
|
|
7
|
+
{
|
|
8
|
+
public static class GDKCIBuildCommand
|
|
9
|
+
{
|
|
10
|
+
private const string KEYSTORE_PASS = "KEYSTORE_PASS";
|
|
11
|
+
private const string KEY_ALIAS_PASS = "KEY_ALIAS_PASS";
|
|
12
|
+
private const string KEY_ALIAS_NAME = "KEY_ALIAS_NAME";
|
|
13
|
+
private const string KEYSTORE = "keystore.keystore";
|
|
14
|
+
private const string BUILD_OPTIONS_ENV_VAR = "BuildOptions";
|
|
15
|
+
private const string ANDROID_BUNDLE_VERSION_CODE = "VERSION_BUILD_VAR";
|
|
16
|
+
private const string ANDROID_APP_BUNDLE = "BUILD_APP_BUNDLE";
|
|
17
|
+
private const string SCRIPTING_BACKEND_ENV_VAR = "SCRIPTING_BACKEND";
|
|
18
|
+
private const string VERSION_NUMBER_VAR = "VERSION_NUMBER_VAR";
|
|
19
|
+
private const string VERSION_iOS = "VERSION_BUILD_VAR";
|
|
20
|
+
|
|
21
|
+
static string GetArgument(string name)
|
|
22
|
+
{
|
|
23
|
+
string[] args = Environment.GetCommandLineArgs();
|
|
24
|
+
for (int i = 0; i < args.Length; i++)
|
|
25
|
+
{
|
|
26
|
+
if (args[i].Contains(name))
|
|
27
|
+
{
|
|
28
|
+
return args[i + 1];
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
static string[] GetEnabledScenes()
|
|
35
|
+
{
|
|
36
|
+
return (
|
|
37
|
+
from scene in EditorBuildSettings.scenes
|
|
38
|
+
where scene.enabled
|
|
39
|
+
where !string.IsNullOrEmpty(scene.path)
|
|
40
|
+
select scene.path
|
|
41
|
+
).ToArray();
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
static BuildTarget GetBuildTarget()
|
|
45
|
+
{
|
|
46
|
+
string buildTargetName = GetArgument("customBuildTarget");
|
|
47
|
+
Console.WriteLine(":: Received customBuildTarget " + buildTargetName);
|
|
48
|
+
|
|
49
|
+
if (buildTargetName.ToLower() == "android")
|
|
50
|
+
{
|
|
51
|
+
#if !UNITY_5_6_OR_NEWER
|
|
52
|
+
// https://issuetracker.unity3d.com/issues/buildoptions-dot-acceptexternalmodificationstoplayer-causes-unityexception-unknown-project-type-0
|
|
53
|
+
// Fixed in Unity 5.6.0
|
|
54
|
+
// side effect to fix android build system:
|
|
55
|
+
EditorUserBuildSettings.androidBuildSystem = AndroidBuildSystem.Internal;
|
|
56
|
+
#endif
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (buildTargetName.TryConvertToEnum(out BuildTarget target))
|
|
60
|
+
return target;
|
|
61
|
+
|
|
62
|
+
Console.WriteLine($":: {nameof(buildTargetName)} \"{buildTargetName}\" not defined on enum {nameof(BuildTarget)}, using {nameof(BuildTarget.NoTarget)} enum to build");
|
|
63
|
+
|
|
64
|
+
return BuildTarget.NoTarget;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
static string GetBuildPath()
|
|
68
|
+
{
|
|
69
|
+
string buildPath = GetArgument("customBuildPath");
|
|
70
|
+
Console.WriteLine(":: Received customBuildPath " + buildPath);
|
|
71
|
+
if (buildPath == "")
|
|
72
|
+
{
|
|
73
|
+
throw new Exception("customBuildPath argument is missing");
|
|
74
|
+
}
|
|
75
|
+
return buildPath;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
static string GetBuildName()
|
|
79
|
+
{
|
|
80
|
+
string buildName = GetArgument("customBuildName");
|
|
81
|
+
Console.WriteLine(":: Received customBuildName " + buildName);
|
|
82
|
+
if (buildName == "")
|
|
83
|
+
{
|
|
84
|
+
throw new Exception("customBuildName argument is missing");
|
|
85
|
+
}
|
|
86
|
+
return buildName;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
static string GetFixedBuildPath(BuildTarget buildTarget, string buildPath, string buildName)
|
|
90
|
+
{
|
|
91
|
+
if (buildTarget.ToString().ToLower().Contains("windows"))
|
|
92
|
+
{
|
|
93
|
+
buildName += ".exe";
|
|
94
|
+
}
|
|
95
|
+
else if (buildTarget == BuildTarget.Android)
|
|
96
|
+
{
|
|
97
|
+
#if UNITY_2018_3_OR_NEWER
|
|
98
|
+
buildName += EditorUserBuildSettings.buildAppBundle ? ".aab" : ".apk";
|
|
99
|
+
#else
|
|
100
|
+
buildName += ".apk";
|
|
101
|
+
#endif
|
|
102
|
+
}
|
|
103
|
+
return buildPath + buildName;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
static BuildOptions GetBuildOptions()
|
|
107
|
+
{
|
|
108
|
+
if (TryGetEnv(BUILD_OPTIONS_ENV_VAR, out string envVar))
|
|
109
|
+
{
|
|
110
|
+
string[] allOptionVars = envVar.Split(',');
|
|
111
|
+
BuildOptions allOptions = BuildOptions.None;
|
|
112
|
+
BuildOptions option;
|
|
113
|
+
string optionVar;
|
|
114
|
+
int length = allOptionVars.Length;
|
|
115
|
+
|
|
116
|
+
Console.WriteLine($":: Detecting {BUILD_OPTIONS_ENV_VAR} env var with {length} elements ({envVar})");
|
|
117
|
+
|
|
118
|
+
for (int i = 0; i < length; i++)
|
|
119
|
+
{
|
|
120
|
+
optionVar = allOptionVars[i];
|
|
121
|
+
|
|
122
|
+
if (optionVar.TryConvertToEnum(out option))
|
|
123
|
+
{
|
|
124
|
+
allOptions |= option;
|
|
125
|
+
}
|
|
126
|
+
else
|
|
127
|
+
{
|
|
128
|
+
Console.WriteLine($":: Cannot convert {optionVar} to {nameof(BuildOptions)} enum, skipping it.");
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return allOptions;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return BuildOptions.None;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// https://stackoverflow.com/questions/1082532/how-to-tryparse-for-enum-value
|
|
139
|
+
static bool TryConvertToEnum<TEnum>(this string strEnumValue, out TEnum value)
|
|
140
|
+
{
|
|
141
|
+
if (!Enum.IsDefined(typeof(TEnum), strEnumValue))
|
|
142
|
+
{
|
|
143
|
+
value = default;
|
|
144
|
+
return false;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
value = (TEnum)Enum.Parse(typeof(TEnum), strEnumValue);
|
|
148
|
+
return true;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
static bool TryGetEnv(string key, out string value)
|
|
152
|
+
{
|
|
153
|
+
value = Environment.GetEnvironmentVariable(key);
|
|
154
|
+
return !string.IsNullOrEmpty(value);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
static void SetScriptingBackendFromEnv(BuildTarget platform)
|
|
158
|
+
{
|
|
159
|
+
var targetGroup = BuildPipeline.GetBuildTargetGroup(platform);
|
|
160
|
+
if (TryGetEnv(SCRIPTING_BACKEND_ENV_VAR, out string scriptingBackend))
|
|
161
|
+
{
|
|
162
|
+
if (scriptingBackend.TryConvertToEnum(out ScriptingImplementation backend))
|
|
163
|
+
{
|
|
164
|
+
Console.WriteLine($":: Setting ScriptingBackend to {backend}");
|
|
165
|
+
PlayerSettings.SetScriptingBackend(targetGroup, backend);
|
|
166
|
+
}
|
|
167
|
+
else
|
|
168
|
+
{
|
|
169
|
+
string possibleValues = string.Join(", ", Enum.GetValues(typeof(ScriptingImplementation)).Cast<ScriptingImplementation>());
|
|
170
|
+
throw new Exception($"Could not find '{scriptingBackend}' in ScriptingImplementation enum. Possible values are: {possibleValues}");
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
else
|
|
174
|
+
{
|
|
175
|
+
var defaultBackend = PlayerSettings.GetDefaultScriptingBackend(targetGroup);
|
|
176
|
+
Console.WriteLine($":: Using project's configured ScriptingBackend (should be {defaultBackend} for targetGroup {targetGroup}");
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
public static void PerformBuild()
|
|
181
|
+
{
|
|
182
|
+
var buildTarget = GetBuildTarget();
|
|
183
|
+
|
|
184
|
+
Console.WriteLine(":: Performing build");
|
|
185
|
+
if (TryGetEnv(VERSION_NUMBER_VAR, out var bundleVersionNumber))
|
|
186
|
+
{
|
|
187
|
+
if (buildTarget == BuildTarget.iOS)
|
|
188
|
+
{
|
|
189
|
+
bundleVersionNumber = GetIosVersion();
|
|
190
|
+
}
|
|
191
|
+
Console.WriteLine($":: Setting bundleVersionNumber to '{bundleVersionNumber}' (Length: {bundleVersionNumber.Length})");
|
|
192
|
+
PlayerSettings.bundleVersion = bundleVersionNumber;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
if (buildTarget == BuildTarget.Android)
|
|
196
|
+
{
|
|
197
|
+
HandleAndroidAppBundle();
|
|
198
|
+
HandleAndroidBundleVersionCode();
|
|
199
|
+
HandleAndroidKeystore();
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
var buildPath = GetBuildPath();
|
|
203
|
+
var buildName = GetBuildName();
|
|
204
|
+
var buildOptions = GetBuildOptions();
|
|
205
|
+
var fixedBuildPath = GetFixedBuildPath(buildTarget, buildPath, buildName);
|
|
206
|
+
|
|
207
|
+
SetScriptingBackendFromEnv(buildTarget);
|
|
208
|
+
|
|
209
|
+
var buildReport = BuildPipeline.BuildPlayer(GetEnabledScenes(), fixedBuildPath, buildTarget, buildOptions);
|
|
210
|
+
|
|
211
|
+
if (buildReport.summary.result != UnityEditor.Build.Reporting.BuildResult.Succeeded)
|
|
212
|
+
throw new Exception($"Build ended with {buildReport.summary.result} status");
|
|
213
|
+
|
|
214
|
+
Console.WriteLine(":: Done with build");
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
private static void HandleAndroidAppBundle()
|
|
218
|
+
{
|
|
219
|
+
if (TryGetEnv(ANDROID_APP_BUNDLE, out string value))
|
|
220
|
+
{
|
|
221
|
+
#if UNITY_2018_3_OR_NEWER
|
|
222
|
+
if (bool.TryParse(value, out bool buildAppBundle))
|
|
223
|
+
{
|
|
224
|
+
EditorUserBuildSettings.buildAppBundle = buildAppBundle;
|
|
225
|
+
Console.WriteLine($":: {ANDROID_APP_BUNDLE} env var detected, set buildAppBundle to {value}.");
|
|
226
|
+
}
|
|
227
|
+
else
|
|
228
|
+
{
|
|
229
|
+
Console.WriteLine($":: {ANDROID_APP_BUNDLE} env var detected but the value \"{value}\" is not a boolean.");
|
|
230
|
+
}
|
|
231
|
+
#else
|
|
232
|
+
Console.WriteLine($":: {ANDROID_APP_BUNDLE} env var detected but does not work with lower Unity version than 2018.3");
|
|
233
|
+
#endif
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
private static void HandleAndroidBundleVersionCode()
|
|
238
|
+
{
|
|
239
|
+
if (TryGetEnv(ANDROID_BUNDLE_VERSION_CODE, out string value))
|
|
240
|
+
{
|
|
241
|
+
if (int.TryParse(value, out int version))
|
|
242
|
+
{
|
|
243
|
+
PlayerSettings.Android.bundleVersionCode = version;
|
|
244
|
+
Console.WriteLine($":: {ANDROID_BUNDLE_VERSION_CODE} env var detected, set the bundle version code to {value}.");
|
|
245
|
+
}
|
|
246
|
+
else
|
|
247
|
+
Console.WriteLine($":: {ANDROID_BUNDLE_VERSION_CODE} env var detected but the version value \"{value}\" is not an integer.");
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
private static string GetIosVersion()
|
|
252
|
+
{
|
|
253
|
+
if (TryGetEnv(VERSION_iOS, out string value))
|
|
254
|
+
{
|
|
255
|
+
if (int.TryParse(value, out int version))
|
|
256
|
+
{
|
|
257
|
+
Console.WriteLine($":: {VERSION_iOS} env var detected, set the version to {value}.");
|
|
258
|
+
return version.ToString();
|
|
259
|
+
}
|
|
260
|
+
else
|
|
261
|
+
Console.WriteLine($":: {VERSION_iOS} env var detected but the version value \"{value}\" is not an integer.");
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
throw new ArgumentNullException(nameof(value), $":: Error finding {VERSION_iOS} env var");
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
private static void HandleAndroidKeystore()
|
|
268
|
+
{
|
|
269
|
+
#if UNITY_2019_1_OR_NEWER
|
|
270
|
+
PlayerSettings.Android.useCustomKeystore = false;
|
|
271
|
+
#endif
|
|
272
|
+
|
|
273
|
+
if (!File.Exists(KEYSTORE))
|
|
274
|
+
{
|
|
275
|
+
Console.WriteLine($":: {KEYSTORE} not found, skipping setup, using Unity's default keystore");
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
PlayerSettings.Android.keystoreName = KEYSTORE;
|
|
280
|
+
|
|
281
|
+
string keystorePass;
|
|
282
|
+
string keystoreAliasPass;
|
|
283
|
+
|
|
284
|
+
if (TryGetEnv(KEY_ALIAS_NAME, out string keyaliasName))
|
|
285
|
+
{
|
|
286
|
+
PlayerSettings.Android.keyaliasName = keyaliasName;
|
|
287
|
+
Console.WriteLine($":: using ${KEY_ALIAS_NAME} env var on PlayerSettings");
|
|
288
|
+
}
|
|
289
|
+
else
|
|
290
|
+
{
|
|
291
|
+
Console.WriteLine($":: ${KEY_ALIAS_NAME} env var not set, using Project's PlayerSettings");
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
if (!TryGetEnv(KEYSTORE_PASS, out keystorePass))
|
|
295
|
+
{
|
|
296
|
+
Console.WriteLine($":: ${KEYSTORE_PASS} env var not set, skipping setup, using Unity's default keystore");
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
if (!TryGetEnv(KEY_ALIAS_PASS, out keystoreAliasPass))
|
|
301
|
+
{
|
|
302
|
+
Console.WriteLine($":: ${KEY_ALIAS_PASS} env var not set, skipping setup, using Unity's default keystore");
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
#if UNITY_2019_1_OR_NEWER
|
|
306
|
+
PlayerSettings.Android.useCustomKeystore = true;
|
|
307
|
+
#endif
|
|
308
|
+
PlayerSettings.Android.keystorePass = keystorePass;
|
|
309
|
+
PlayerSettings.Android.keyaliasPass = keystoreAliasPass;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -22,34 +22,52 @@ namespace Amanotes.Core
|
|
|
22
22
|
|
|
23
23
|
public class EventParams : IEventParamsBuilder
|
|
24
24
|
{
|
|
25
|
-
public
|
|
26
|
-
public Dictionary<string, object> parameters = new Dictionary<string, object>();
|
|
25
|
+
public string eventName { get; private set; }
|
|
26
|
+
public readonly Dictionary<string, object> parameters = new Dictionary<string, object>();
|
|
27
27
|
public string funnelSignature;
|
|
28
28
|
public bool accumulated;
|
|
29
29
|
public bool withinSession;
|
|
30
30
|
public bool doNotIncreaseCounter;
|
|
31
31
|
|
|
32
32
|
public bool overrideConfig;
|
|
33
|
-
public HashSet<string> ignoreAdapterIds =
|
|
34
|
-
public HashSet<string> allowAdapterIds =
|
|
33
|
+
public HashSet<string> ignoreAdapterIds = null;
|
|
34
|
+
public HashSet<string> allowAdapterIds = null;
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
private EventDetail _detail;
|
|
37
|
+
public EventDetail EventDetail
|
|
38
|
+
{
|
|
39
|
+
get
|
|
40
|
+
{
|
|
41
|
+
if (_detail != null) return _detail;
|
|
42
|
+
return _detail = localData.GetEventDetail(eventName, true);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
37
45
|
|
|
38
|
-
|
|
46
|
+
internal EventParams Init(string eventName)
|
|
39
47
|
{
|
|
40
48
|
this.eventName = eventName;
|
|
49
|
+
parameters.Clear();
|
|
50
|
+
funnelSignature = "";
|
|
51
|
+
accumulated = false;
|
|
52
|
+
withinSession = false;
|
|
53
|
+
doNotIncreaseCounter = false;
|
|
54
|
+
overrideConfig = false;
|
|
55
|
+
ignoreAdapterIds = null;
|
|
56
|
+
allowAdapterIds = null;
|
|
57
|
+
_detail = null;
|
|
58
|
+
return this;
|
|
41
59
|
}
|
|
42
60
|
|
|
43
61
|
public bool IsFunnelEvent => !string.IsNullOrEmpty(funnelSignature);
|
|
44
62
|
|
|
45
63
|
public bool IsAdapterForbidden(string adapterId)
|
|
46
64
|
{
|
|
47
|
-
if (ignoreAdapterIds.Count > 0)
|
|
65
|
+
if (ignoreAdapterIds != null && ignoreAdapterIds.Count > 0)
|
|
48
66
|
{
|
|
49
67
|
return ignoreAdapterIds.Contains(adapterId);
|
|
50
68
|
}
|
|
51
69
|
|
|
52
|
-
if (allowAdapterIds.Count > 0)
|
|
70
|
+
if (allowAdapterIds != null && allowAdapterIds.Count > 0)
|
|
53
71
|
{
|
|
54
72
|
return !allowAdapterIds.Contains(adapterId);
|
|
55
73
|
}
|
|
@@ -164,12 +182,13 @@ namespace Amanotes.Core
|
|
|
164
182
|
}
|
|
165
183
|
|
|
166
184
|
if (eventCountMap != null)
|
|
185
|
+
{
|
|
167
186
|
foreach (KeyValuePair<string, int> e in eventCountMap)
|
|
168
187
|
{
|
|
169
188
|
EventDetail eventDetail = localData.GetEventDetail(e.Key);
|
|
170
189
|
if (eventDetail == null)
|
|
171
190
|
{
|
|
172
|
-
localData.
|
|
191
|
+
localData.AddEventDetail(new EventDetail
|
|
173
192
|
{
|
|
174
193
|
eventName = e.Key,
|
|
175
194
|
totalCount = e.Value
|
|
@@ -188,6 +207,8 @@ namespace Amanotes.Core
|
|
|
188
207
|
eventDetail.totalCount += e.Value;
|
|
189
208
|
}
|
|
190
209
|
}
|
|
210
|
+
}
|
|
211
|
+
|
|
191
212
|
|
|
192
213
|
Profiler.EndSample();
|
|
193
214
|
return flag;
|
|
@@ -252,8 +273,10 @@ namespace Amanotes.Core
|
|
|
252
273
|
internal static Predicate<EventParams> logEventHook;
|
|
253
274
|
internal static readonly ConcurrentQueue<EventParams> eventQueue = new ConcurrentQueue<EventParams>();
|
|
254
275
|
internal static readonly List<AnalyticsAdapter> listAdapters = new List<AnalyticsAdapter>();
|
|
255
|
-
internal static readonly AnalyticsData localData = new AnalyticsData().LoadJsonFromFile();
|
|
256
|
-
internal static readonly SessionStat sessionStat = new SessionStat();
|
|
276
|
+
internal static readonly AnalyticsData localData = new AnalyticsData().LoadJsonFromFile().BuildCache();
|
|
277
|
+
internal static readonly SessionStat sessionStat = _config.analytics.enableEventStat ? new SessionStat() : null;
|
|
278
|
+
internal static readonly Pool<StringBuilder> sbPool = new Pool<StringBuilder>(3);
|
|
279
|
+
internal static readonly Pool<EventParams> epPool = new Pool<EventParams>(1);
|
|
257
280
|
|
|
258
281
|
internal static readonly Dictionary<string, string> reservedPrefixes = new Dictionary<string, string>()
|
|
259
282
|
{
|
|
@@ -315,7 +338,7 @@ namespace Amanotes.Core
|
|
|
315
338
|
internal static EventParams PrepareEvent(string eventName)
|
|
316
339
|
{
|
|
317
340
|
PrepareEventCheck(eventName);
|
|
318
|
-
var result =
|
|
341
|
+
var result = epPool.Get().Init(eventName);
|
|
319
342
|
PostPrepareEventProcess(result);
|
|
320
343
|
return result;
|
|
321
344
|
}
|
|
@@ -324,7 +347,7 @@ namespace Amanotes.Core
|
|
|
324
347
|
{
|
|
325
348
|
if (parameters == null) return PrepareEvent(eventName);
|
|
326
349
|
PrepareEventCheck(eventName);
|
|
327
|
-
var result =
|
|
350
|
+
var result = epPool.Get().Init(eventName);
|
|
328
351
|
result.AddParam(parameters);
|
|
329
352
|
PostPrepareEventProcess(result);
|
|
330
353
|
return result;
|
|
@@ -334,7 +357,7 @@ namespace Amanotes.Core
|
|
|
334
357
|
{
|
|
335
358
|
if (parameters == null) return PrepareEvent(eventName);
|
|
336
359
|
PrepareEventCheck(eventName);
|
|
337
|
-
var result =
|
|
360
|
+
var result = epPool.Get().Init(eventName);
|
|
338
361
|
for (var i = 0; i < parameters.Length; i++)
|
|
339
362
|
{
|
|
340
363
|
result.AddParam(parameters[i].Item1, parameters[i].Item2);
|
|
@@ -348,18 +371,18 @@ namespace Amanotes.Core
|
|
|
348
371
|
if (eventQueue.Count <= 0) return;
|
|
349
372
|
|
|
350
373
|
Profiler.BeginSample("AmaGDK.Analytics.ProcessEventQueue()");
|
|
351
|
-
|
|
352
|
-
sessionStat
|
|
374
|
+
|
|
375
|
+
sessionStat?.Clear();
|
|
353
376
|
|
|
354
377
|
while (eventQueue.TryDequeue(out var eventData))
|
|
355
378
|
{
|
|
356
379
|
var (eventNameToSend, inUseAdapterIDs) = LogEventActually(eventData);
|
|
357
|
-
|
|
358
|
-
|
|
380
|
+
sessionStat?.Add(eventNameToSend, eventData, inUseAdapterIDs);
|
|
381
|
+
epPool.Return(eventData);
|
|
359
382
|
}
|
|
360
383
|
|
|
361
384
|
localData.SaveIfDirty();
|
|
362
|
-
sessionStat
|
|
385
|
+
sessionStat?.Save();
|
|
363
386
|
Profiler.EndSample();
|
|
364
387
|
}
|
|
365
388
|
|
|
@@ -384,7 +407,7 @@ namespace Amanotes.Core
|
|
|
384
407
|
|
|
385
408
|
config.quality.CheckEventQuality(eventParams.eventName, eventParams.parameters);
|
|
386
409
|
|
|
387
|
-
var inUseAdapterIDs = new List<string>();
|
|
410
|
+
var inUseAdapterIDs = config.enableEventStat ? new List<string>(listAdapters.Count) : null;
|
|
388
411
|
foreach (AnalyticsAdapter m in listAdapters)
|
|
389
412
|
{
|
|
390
413
|
if (eventParams.overrideConfig)
|
|
@@ -400,7 +423,7 @@ namespace Amanotes.Core
|
|
|
400
423
|
if (m.IsForbidden(eventParams.eventName)) continue;
|
|
401
424
|
}
|
|
402
425
|
m.LogEvent(eventNameToSend, eventParams.parameters);
|
|
403
|
-
inUseAdapterIDs
|
|
426
|
+
inUseAdapterIDs?.Add(m.adapterId);
|
|
404
427
|
}
|
|
405
428
|
|
|
406
429
|
return (eventNameToSend, inUseAdapterIDs);
|
|
@@ -409,9 +432,9 @@ namespace Amanotes.Core
|
|
|
409
432
|
internal static void LogEventImmediately(EventParams eventParams)
|
|
410
433
|
{
|
|
411
434
|
var (eventNameToSend, inUseAdapterIDs) = LogEventActually(eventParams);
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
sessionStat
|
|
435
|
+
sessionStat?.Add(eventNameToSend, eventParams, inUseAdapterIDs);
|
|
436
|
+
epPool.Return(eventParams);
|
|
437
|
+
sessionStat?.Save();
|
|
415
438
|
localData.SaveIfDirty();
|
|
416
439
|
}
|
|
417
440
|
|
|
@@ -452,12 +475,13 @@ namespace Amanotes.Core
|
|
|
452
475
|
{
|
|
453
476
|
Profiler.BeginSample("AmaGDK.Analytics.NormalizeEventName()");
|
|
454
477
|
{
|
|
455
|
-
StringBuilder sb =
|
|
478
|
+
StringBuilder sb = sbPool.Get();
|
|
456
479
|
sb.Clear();
|
|
457
480
|
NormalizeKeyString(ref eventName, sb, dryRun);
|
|
458
481
|
if (reservedEvents.Contains(eventName))
|
|
459
482
|
sb.AppendLine($" - EventName <{eventName}> is reserved and should not be used");
|
|
460
|
-
if (sb.Length > 0 && dryRun) LogWarningOnce($"Warning for event name <{eventName}>:\n{sb}", $"NormalizeEventName<{eventName}>");
|
|
483
|
+
if (sb.Length > 0 && dryRun) LogWarningOnce($"Warning for event name <{eventName}>:\n{sb}", $"NormalizeEventName<{eventName}>");
|
|
484
|
+
sbPool.Return(sb);
|
|
461
485
|
}
|
|
462
486
|
Profiler.EndSample();
|
|
463
487
|
}
|
|
@@ -473,57 +497,103 @@ namespace Amanotes.Core
|
|
|
473
497
|
return;
|
|
474
498
|
}
|
|
475
499
|
|
|
476
|
-
var
|
|
500
|
+
var tempLog = Config.common.logLevel == LogLevel.None ? null : sbPool.Get();
|
|
501
|
+
tempLog?.Clear();
|
|
477
502
|
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
503
|
+
var tempKey = sbPool.Get();
|
|
504
|
+
tempKey.Clear();
|
|
505
|
+
|
|
506
|
+
var hasChanged = false;
|
|
507
|
+
var trimKey = key.Trim();
|
|
508
|
+
|
|
509
|
+
foreach (var c in trimKey)
|
|
482
510
|
{
|
|
483
|
-
|
|
511
|
+
var isLetter = IsAlphabet(c);
|
|
512
|
+
var isNumber = char.IsDigit(c);
|
|
513
|
+
|
|
514
|
+
if (c == '_' || isLetter || isNumber)
|
|
515
|
+
{
|
|
516
|
+
tempKey.Append(c);
|
|
517
|
+
continue;
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
hasChanged = true;
|
|
521
|
+
if (c == ' ' || c == '-')
|
|
522
|
+
{
|
|
523
|
+
tempKey.Append('_');
|
|
524
|
+
}
|
|
484
525
|
}
|
|
485
526
|
|
|
486
|
-
|
|
487
|
-
if (!r.IsMatch(normalizedString))
|
|
527
|
+
if (hasChanged)
|
|
488
528
|
{
|
|
489
|
-
|
|
490
|
-
sb.Append(" - Name may only contain alphanumeric characters and underscores");
|
|
529
|
+
tempLog?.Append(" - Name may only contain alphanumeric characters and underscores");
|
|
491
530
|
}
|
|
492
|
-
|
|
493
|
-
if (!
|
|
531
|
+
|
|
532
|
+
if (tempKey.Length > 0 && !IsAlphabet(tempKey[0]))
|
|
494
533
|
{
|
|
495
|
-
|
|
496
|
-
|
|
534
|
+
hasChanged = true;
|
|
535
|
+
tempKey.Insert(0, 'E');
|
|
536
|
+
tempLog?.Append($" - Name must start with a letter: <{key}>");
|
|
497
537
|
}
|
|
498
|
-
|
|
538
|
+
|
|
499
539
|
foreach (var prefix in reservedPrefixes)
|
|
500
540
|
{
|
|
501
|
-
if (!
|
|
502
|
-
|
|
503
|
-
|
|
541
|
+
if (tempKey.Length < prefix.Key.Length || !StringStartsWith(tempKey, prefix.Key)) continue;
|
|
542
|
+
hasChanged = true;
|
|
543
|
+
tempKey.Remove(0, prefix.Key.Length);
|
|
544
|
+
tempKey.Insert(0, prefix.Value);
|
|
545
|
+
tempLog?.AppendLine($" - <{key}> starts with reserved prefix <{prefix}>");
|
|
504
546
|
}
|
|
505
547
|
|
|
506
|
-
if (
|
|
548
|
+
if (trimKey.Length > 40)
|
|
507
549
|
{
|
|
508
|
-
|
|
509
|
-
|
|
550
|
+
hasChanged = true;
|
|
551
|
+
tempLog?.AppendLine($" - Name is too long ({key.Length} > 40): <{key}> ");
|
|
552
|
+
tempKey.Length = 40;
|
|
510
553
|
}
|
|
511
554
|
|
|
512
555
|
if (dryRun)
|
|
513
556
|
{
|
|
514
|
-
warningLog.Append(
|
|
557
|
+
warningLog.Append(tempLog);
|
|
515
558
|
} else {
|
|
516
|
-
key =
|
|
559
|
+
if (hasChanged) key = tempKey.ToString();
|
|
517
560
|
}
|
|
561
|
+
|
|
562
|
+
if (tempLog != null) sbPool.Return(tempLog);
|
|
563
|
+
sbPool.Return(tempKey);
|
|
518
564
|
}
|
|
519
565
|
Profiler.EndSample();
|
|
520
566
|
}
|
|
567
|
+
|
|
568
|
+
private static bool StringStartsWith(StringBuilder stringBuilder, string prefix)
|
|
569
|
+
{
|
|
570
|
+
if (stringBuilder == null || prefix == null)
|
|
571
|
+
return false;
|
|
572
|
+
|
|
573
|
+
if (stringBuilder.Length < prefix.Length)
|
|
574
|
+
return false;
|
|
575
|
+
|
|
576
|
+
for (int i = 0; i < prefix.Length; i++)
|
|
577
|
+
{
|
|
578
|
+
if (stringBuilder[i] != prefix[i])
|
|
579
|
+
return false;
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
return true;
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
private static bool IsAlphabet(char c)
|
|
586
|
+
{
|
|
587
|
+
if (c >= 'A' && c <= 'Z') return true;
|
|
588
|
+
if (c >= 'a' && c <= 'z') return true;
|
|
589
|
+
return false;
|
|
590
|
+
}
|
|
521
591
|
|
|
522
592
|
internal static void PrepareEventCheck(string eventName)
|
|
523
593
|
{
|
|
524
594
|
NormalizeEventName(ref eventName, true);
|
|
525
595
|
|
|
526
|
-
if (localData.GetEventDetail(eventName) == null && localData.
|
|
596
|
+
if (localData.GetEventDetail(eventName) == null && localData.totalEventDetailCount >= 500)
|
|
527
597
|
{
|
|
528
598
|
LogWarning($" - You have reported 500 types of events. New event <{eventName}> will be ignored.");
|
|
529
599
|
}
|
|
@@ -625,23 +695,63 @@ namespace Amanotes.Core
|
|
|
625
695
|
internal class AnalyticsData : IJsonFile
|
|
626
696
|
{
|
|
627
697
|
public List<string> funnelSignatures = new List<string>();
|
|
628
|
-
|
|
698
|
+
|
|
629
699
|
public MigrationLog migrationLog = new MigrationLog();
|
|
630
700
|
[NonSerialized] internal bool _dirty;
|
|
631
|
-
|
|
701
|
+
|
|
702
|
+
[SerializeField] internal List<EventDetail> eventDetails = new List<EventDetail>();
|
|
703
|
+
internal readonly Dictionary<string, EventDetail> cachedEventDetails = new Dictionary<string, EventDetail>();
|
|
704
|
+
|
|
705
|
+
public int totalEventDetailCount => eventDetails.Count;
|
|
706
|
+
public bool AddEventDetail(EventDetail ed)
|
|
707
|
+
{
|
|
708
|
+
if (cachedEventDetails.ContainsKey(ed.eventName))
|
|
709
|
+
{
|
|
710
|
+
Debug.LogWarning($"EventName <{ed.eventName}> existed!");
|
|
711
|
+
return false;
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
eventDetails.Add(ed);
|
|
715
|
+
cachedEventDetails.Add(ed.eventName, ed);
|
|
716
|
+
return true;
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
internal AnalyticsData BuildCache()
|
|
720
|
+
{
|
|
721
|
+
if (cachedEventDetails.Count > 0)
|
|
722
|
+
{
|
|
723
|
+
LogWarning("BuildCache should be called once!");
|
|
724
|
+
cachedEventDetails.Clear();
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
for (var i = 0; i < eventDetails.Count; i++)
|
|
728
|
+
{
|
|
729
|
+
var item = eventDetails[i];
|
|
730
|
+
if (cachedEventDetails.ContainsKey(item.eventName))
|
|
731
|
+
{
|
|
732
|
+
LogWarning($"Duplicated eventName <{item.eventName}> entry found in AnalyticData!");
|
|
733
|
+
continue;
|
|
734
|
+
}
|
|
735
|
+
cachedEventDetails.Add(item.eventName, item);
|
|
736
|
+
}
|
|
737
|
+
return this;
|
|
738
|
+
}
|
|
739
|
+
|
|
632
740
|
internal EventDetail GetEventDetail(string eventName, bool autoNew = false)
|
|
633
741
|
{
|
|
634
742
|
if (string.IsNullOrEmpty(eventName)) return null;
|
|
635
743
|
|
|
636
|
-
|
|
637
|
-
|
|
744
|
+
if (cachedEventDetails.TryGetValue(eventName, out var result))
|
|
745
|
+
{
|
|
746
|
+
return result;
|
|
747
|
+
}
|
|
638
748
|
if (autoNew == false) return null;
|
|
639
749
|
|
|
640
750
|
result = new EventDetail
|
|
641
751
|
{
|
|
642
752
|
eventName = eventName
|
|
643
753
|
};
|
|
644
|
-
|
|
754
|
+
AddEventDetail(result);
|
|
645
755
|
_dirty = true;
|
|
646
756
|
return result;
|
|
647
757
|
}
|
|
@@ -706,14 +816,13 @@ namespace Amanotes.Core
|
|
|
706
816
|
|
|
707
817
|
internal void Add(string eventNameToSend, EventParams eventParams, List<string> adapterIDs)
|
|
708
818
|
{
|
|
819
|
+
if (string.IsNullOrEmpty(eventNameToSend) || adapterIDs == null) return;
|
|
709
820
|
var eventStat = new EventStat(eventNameToSend, eventParams, adapterIDs);
|
|
710
821
|
lastFrameEventStats.Enqueue(eventStat);
|
|
711
822
|
}
|
|
712
823
|
|
|
713
824
|
internal void Save()
|
|
714
825
|
{
|
|
715
|
-
if (!Config.analytics.enableEventStat || lastFrameEventStats.Count == 0) return;
|
|
716
|
-
|
|
717
826
|
contents.Clear();
|
|
718
827
|
if (isFirstSave)
|
|
719
828
|
{
|
|
@@ -728,9 +837,19 @@ namespace Amanotes.Core
|
|
|
728
837
|
|
|
729
838
|
GDKFileUtils.SaveAppend(fileName, contents.ToString());
|
|
730
839
|
}
|
|
840
|
+
|
|
841
|
+
internal void Clear()
|
|
842
|
+
{
|
|
843
|
+
//Clear() is supported from .Net Standard 2.1
|
|
844
|
+
#if UNITY_2021_3_OR_NEWER
|
|
845
|
+
sessionStat?.savedEventStatsInLastFrame.Clear();
|
|
846
|
+
#else
|
|
847
|
+
while (savedEventStatsInLastFrame.TryDequeue(out var stat))
|
|
848
|
+
{
|
|
849
|
+
}
|
|
850
|
+
#endif
|
|
851
|
+
}
|
|
731
852
|
}
|
|
732
|
-
|
|
733
|
-
|
|
734
853
|
}
|
|
735
854
|
}
|
|
736
855
|
|
|
@@ -781,6 +900,8 @@ namespace Amanotes.Core
|
|
|
781
900
|
}
|
|
782
901
|
|
|
783
902
|
eventData.overrideConfig = true;
|
|
903
|
+
eventData.ignoreAdapterIds ??= new HashSet<string>();
|
|
904
|
+
|
|
784
905
|
foreach (string mId in analyticIds)
|
|
785
906
|
{
|
|
786
907
|
eventData.ignoreAdapterIds.Add(mId);
|
|
@@ -805,6 +926,8 @@ namespace Amanotes.Core
|
|
|
805
926
|
}
|
|
806
927
|
|
|
807
928
|
eventData.overrideConfig = true;
|
|
929
|
+
eventData.allowAdapterIds ??= new HashSet<string>();
|
|
930
|
+
|
|
808
931
|
foreach (string mId in analyticIds)
|
|
809
932
|
{
|
|
810
933
|
eventData.allowAdapterIds.Add(mId);
|
|
@@ -879,11 +1002,12 @@ namespace Amanotes.Core
|
|
|
879
1002
|
{
|
|
880
1003
|
string eventName = (ap as EventParams)?.eventName;
|
|
881
1004
|
|
|
882
|
-
StringBuilder sb =
|
|
1005
|
+
StringBuilder sb = sbPool.Get();
|
|
883
1006
|
sb.Clear();
|
|
884
1007
|
NormalizeKeyString(ref key, sb, AmaGDK.Config.analytics.normalizeEventName);
|
|
885
1008
|
|
|
886
1009
|
if (sb.Length > 0) LogWarningOnce($"Warning for event <{eventName}>, param <{key}>:\n{sb}", $"NormalizeParamKey <{eventName}>");
|
|
1010
|
+
sbPool.Return(sb);
|
|
887
1011
|
|
|
888
1012
|
if (string.IsNullOrWhiteSpace(key))
|
|
889
1013
|
{
|
package/Runtime/AmaGDK.cs
CHANGED
|
@@ -93,6 +93,27 @@ namespace Amanotes.Core.Internal
|
|
|
93
93
|
|
|
94
94
|
public static class Forbidden
|
|
95
95
|
{
|
|
96
|
+
private static bool presetShowAnalyticsLog;
|
|
97
|
+
private static bool presetEnableEventStat;
|
|
98
|
+
private static LogLevel presetLogLevel = LogLevel.Warning;
|
|
99
|
+
|
|
100
|
+
public static void PresetConfig()
|
|
101
|
+
{
|
|
102
|
+
presetLogLevel = Config.common.logLevel;
|
|
103
|
+
Config.common.logLevel = LogLevel.Warning;
|
|
104
|
+
presetShowAnalyticsLog = Config.analytics.showAnalyticsLog;
|
|
105
|
+
Config.analytics.showAnalyticsLog = true;
|
|
106
|
+
presetEnableEventStat = Config.analytics.enableEventStat;
|
|
107
|
+
Config.analytics.enableEventStat = true;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
public static void ReloadConfig()
|
|
111
|
+
{
|
|
112
|
+
Config.analytics.showAnalyticsLog = presetShowAnalyticsLog;
|
|
113
|
+
Config.analytics.enableEventStat = presetEnableEventStat;
|
|
114
|
+
Config.common.logLevel = presetLogLevel;
|
|
115
|
+
}
|
|
116
|
+
|
|
96
117
|
public static void DestroyAndReset()
|
|
97
118
|
{
|
|
98
119
|
if (_instance != null)
|
|
@@ -139,9 +160,12 @@ namespace Amanotes.Core.Internal
|
|
|
139
160
|
public static void ClearAnalyticsData()
|
|
140
161
|
{
|
|
141
162
|
AnalyticsData analyticsData = localData;
|
|
163
|
+
analyticsData._dirty = true;
|
|
142
164
|
analyticsData.funnelSignatures.Clear();
|
|
143
165
|
analyticsData.eventDetails.Clear();
|
|
166
|
+
analyticsData.cachedEventDetails.Clear();
|
|
144
167
|
analyticsData.migrationLog = new MigrationLog();
|
|
168
|
+
analyticsData.SaveIfDirty();
|
|
145
169
|
}
|
|
146
170
|
}
|
|
147
171
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
using System;
|
|
2
2
|
using System.Collections;
|
|
3
|
+
using System.Collections.Concurrent;
|
|
3
4
|
using System.Collections.Generic;
|
|
4
5
|
using System.IO;
|
|
5
6
|
using System.Reflection;
|
|
@@ -391,7 +392,6 @@ namespace Amanotes.Core.Internal
|
|
|
391
392
|
|
|
392
393
|
internal interface IJsonFile { }
|
|
393
394
|
|
|
394
|
-
|
|
395
395
|
internal static class JsonFileExtension
|
|
396
396
|
{
|
|
397
397
|
public static T LoadJsonFromFile<T>(this T instance) where T : IJsonFile, new()
|
|
@@ -569,4 +569,30 @@ namespace Amanotes.Core.Internal
|
|
|
569
569
|
// public T[] items;
|
|
570
570
|
//}
|
|
571
571
|
}
|
|
572
|
+
|
|
573
|
+
internal class Pool<T> where T : new()
|
|
574
|
+
{
|
|
575
|
+
private readonly ConcurrentQueue<T> _pool;
|
|
576
|
+
|
|
577
|
+
public Pool(int initialCapacity)
|
|
578
|
+
{
|
|
579
|
+
_pool = new ConcurrentQueue<T>();
|
|
580
|
+
for (int i = 0; i < initialCapacity; i++)
|
|
581
|
+
{
|
|
582
|
+
_pool.Enqueue(new T());
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
public T Get()
|
|
587
|
+
{
|
|
588
|
+
return _pool.TryDequeue(out var obj) ? obj : new T();
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
public void Return(T obj)
|
|
592
|
+
{
|
|
593
|
+
_pool.Enqueue(obj);
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
public int Count => _pool.Count;
|
|
597
|
+
}
|
|
572
598
|
}
|
package/package.json
CHANGED
|
Binary file
|