com.amanotes.gdk 0.2.13 → 0.2.16

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.
Files changed (30) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/Editor/EmbedRemoteConfigAssetInspector.cs +191 -0
  3. package/Editor/EmbedRemoteConfigAssetInspector.cs.meta +11 -0
  4. package/Editor/MatchSDKVersion.cs +151 -0
  5. package/Editor/MatchSDKVersion.cs.meta +11 -0
  6. package/Editor/Utils/AmaGDKEditor.ExtractVersion.cs +1 -1
  7. package/Editor/Utils/AmaGDKEditor.Utils.cs +52 -0
  8. package/Extra/AmaGDKInstaller.unitypackage +0 -0
  9. package/Extra/AmaGDKProject.unitypackage +0 -0
  10. package/Packages/AdjustAdapter_v4.33.0.unitypackage +0 -0
  11. package/Packages/AmaGDKConfig.unitypackage +0 -0
  12. package/Packages/AmaGDKExample.unitypackage +0 -0
  13. package/Packages/AmaGDKTest.unitypackage +0 -0
  14. package/Packages/AmaPassport.ATTSupport.unitypackage +0 -0
  15. package/Packages/AmaPassportAdapter_v1.0.0.unitypackage +0 -0
  16. package/Packages/AppsFlyerAdapter_v6.5.4.unitypackage +0 -0
  17. package/Packages/FirebaseAnalyticsAdapter_v9.1.0.unitypackage +0 -0
  18. package/Packages/FirebaseRemoteConfigAdapter_v9.1.0.unitypackage +0 -0
  19. package/Packages/IronsourceAdapter_v7.2.6.unitypackage +0 -0
  20. package/Runtime/AmaGDK.AmaPassport.cs +1 -0
  21. package/Runtime/AmaGDK.Analytics.cs +22 -3
  22. package/Runtime/AmaGDK.IAP.cs +423 -0
  23. package/Runtime/AmaGDK.IAP.cs.meta +11 -0
  24. package/Runtime/AmaGDK.RemoteConfig.cs +73 -43
  25. package/Runtime/AmaGDK.cs +3 -2
  26. package/Runtime/AnalyticQualityAsset.cs +218 -0
  27. package/Runtime/AnalyticQualityAsset.cs.meta +11 -0
  28. package/Runtime/EmbedRemoteConfigAsset.cs +59 -0
  29. package/Runtime/EmbedRemoteConfigAsset.cs.meta +11 -0
  30. package/package.json +2 -2
package/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.2.14 - 2023-08-08]
4
+ ### Support multiple embed remote config and load config by id
5
+ ### Clear cached remote config on new app update
6
+ ### Override remote config value in editor mode
7
+ ### New feature: Analytics Quality
8
+
3
9
  ## [0.2.13 - 2023-07-20]
4
10
  ### Fix error Remote Config JSON caused by special chars (", ', \)
5
11
 
@@ -0,0 +1,191 @@
1
+ using System;
2
+ using System.Text;
3
+ using Amanotes.Core.Internal;
4
+ using UnityEditor;
5
+ using UnityEngine;
6
+
7
+ using static Amanotes.Core.Internal.Logging;
8
+
9
+ namespace Amanotes.Editor
10
+ {
11
+ [CustomEditor(typeof(EmbedRemoteConfigAsset))]
12
+ internal class EmbedRemoteConfigAssetInspector : UnityEditor.Editor
13
+ {
14
+ private EmbedRemoteConfigAsset remoteConfigAsset;
15
+ private SerializedProperty overrideInEditorProperty;
16
+ private SerializedProperty overrideConfigProperty;
17
+ private SerializedProperty configsProperty;
18
+ private bool[] foldouts;
19
+
20
+ private void OnEnable()
21
+ {
22
+ remoteConfigAsset = (EmbedRemoteConfigAsset)target;
23
+ overrideInEditorProperty = serializedObject.FindProperty("overrideInEditor");
24
+ overrideConfigProperty = serializedObject.FindProperty("overrideConfig");
25
+ configsProperty = serializedObject.FindProperty("configs");
26
+ foldouts = new bool[configsProperty.arraySize];
27
+ }
28
+
29
+ public override void OnInspectorGUI()
30
+ {
31
+ EditorGUILayout.BeginHorizontal();
32
+ EditorGUILayout.LabelField("Active Id:");
33
+ EditorGUILayout.LabelField(remoteConfigAsset.activeId);
34
+ EditorGUILayout.EndHorizontal();
35
+
36
+ serializedObject.Update();
37
+
38
+ DrawPropertiesExcluding(serializedObject, "m_Script", "activeId", "configs", "overrideConfig");
39
+
40
+ if (overrideInEditorProperty.boolValue)
41
+ {
42
+ EditorGUILayout.PropertyField(overrideConfigProperty);
43
+ }
44
+
45
+ if (GUILayout.Button("Add a config set"))
46
+ {
47
+ configsProperty.arraySize++;
48
+ int lastIndex = configsProperty.arraySize - 1;
49
+ var config= configsProperty.GetArrayElementAtIndex(lastIndex);
50
+ config.FindPropertyRelative("id").stringValue = $"config{lastIndex}";
51
+ foldouts = AddElementToArray(foldouts, false);
52
+ }
53
+
54
+ for (int i = 0; i < configsProperty.arraySize; i++)
55
+ {
56
+ SerializedProperty configProperty = configsProperty.GetArrayElementAtIndex(i);
57
+ SerializedProperty idProperty = configProperty.FindPropertyRelative("id");
58
+ SerializedProperty fetchUrlProperty = configProperty.FindPropertyRelative("fetchUrl");
59
+ SerializedProperty itemsProperty = configProperty.FindPropertyRelative("items");
60
+
61
+ EditorGUILayout.BeginVertical(GUI.skin.box);
62
+ foldouts[i] = EditorGUILayout.Foldout(foldouts[i], idProperty.stringValue);
63
+ if (foldouts[i])
64
+ {
65
+ EditorGUI.indentLevel++;
66
+ EditorGUILayout.BeginHorizontal();
67
+ if (GUILayout.Button("Set active", GUILayout.MinWidth(100)))
68
+ {
69
+ remoteConfigAsset.SetActiveConfig(idProperty.stringValue);
70
+ }
71
+ if (GUILayout.Button("Fetch", GUILayout.MinWidth(80)))
72
+ {
73
+ var url = fetchUrlProperty.stringValue;
74
+ var currentConfigIndex = i;
75
+ if (string.IsNullOrWhiteSpace(url))
76
+ {
77
+ ShowError("Please fill the fetch URL first");
78
+ }
79
+ else
80
+ {
81
+ WebRequest.Get(url, onProgress: FetchProgress, onSuccess: s => FillEmbedConfig(currentConfigIndex, s), onError:ShowError);
82
+ }
83
+ }
84
+ if (GUILayout.Button("Remove", GUILayout.MinWidth(80)))
85
+ {
86
+ if (remoteConfigAsset.ActiveConfig?.id == idProperty.stringValue)
87
+ {
88
+ remoteConfigAsset.SetActiveConfig(string.Empty);
89
+ }
90
+ configsProperty.DeleteArrayElementAtIndex(i);
91
+ foldouts = RemoveElementAtIndex(foldouts, i);
92
+ }
93
+ if (GUILayout.Button("Copy", GUILayout.MinWidth(80)))
94
+ {
95
+ GUIUtility.systemCopyBuffer = KeyValueToText(itemsProperty);
96
+ }
97
+ if (GUILayout.Button("Paste", GUILayout.MinWidth(80)))
98
+ {
99
+ FillEmbedConfig(i, GUIUtility.systemCopyBuffer);
100
+ }
101
+ EditorGUILayout.EndHorizontal();
102
+ EditorGUILayout.PropertyField(idProperty);
103
+ EditorGUILayout.PropertyField(fetchUrlProperty);
104
+ EditorGUILayout.PropertyField(itemsProperty);
105
+
106
+ EditorGUI.indentLevel--;
107
+ }
108
+ EditorGUILayout.EndVertical();
109
+ }
110
+
111
+ serializedObject.ApplyModifiedProperties();
112
+ }
113
+
114
+ private T[] AddElementToArray<T>(T[] array, T element)
115
+ {
116
+ T[] newArray = new T[array.Length + 1];
117
+ array.CopyTo(newArray, 0);
118
+ newArray[array.Length] = element;
119
+ return newArray;
120
+ }
121
+
122
+ private T[] RemoveElementAtIndex<T>(T[] array, int index)
123
+ {
124
+ T[] newArray = new T[array.Length - 1];
125
+ for (int i = 0, j = 0; i < array.Length; i++)
126
+ {
127
+ if (i != index)
128
+ {
129
+ newArray[j] = array[i];
130
+ j++;
131
+ }
132
+ }
133
+ return newArray;
134
+ }
135
+
136
+ private void FetchProgress(float progress)
137
+ {
138
+ EditorUtility.DisplayProgressBar("Fetching default remote config", "Please wait...", progress);
139
+ }
140
+
141
+ private void FillEmbedConfig(int configIndex, string rawText)
142
+ {
143
+ try
144
+ {
145
+ string[] lines = rawText.Split('\n');
146
+ KeyValue[] arrKeyValue = new KeyValue[lines.Length];
147
+ for (int i = 0; i < lines.Length; i++)
148
+ {
149
+ var line = lines[i];
150
+ var idx = line.IndexOf('\t');
151
+ if (idx == -1)
152
+ {
153
+ LogWarning($"[RemoteConfig] Cannot get (key, value) at line {i+1}. Content:\n<{line}>");
154
+ continue;
155
+ }
156
+ arrKeyValue[i] = new KeyValue
157
+ {
158
+ key = line.Substring(0, idx),
159
+ value = line.Substring(idx + 1)
160
+ };
161
+ }
162
+ remoteConfigAsset.configs[configIndex].items = arrKeyValue;
163
+ }
164
+ catch (Exception e)
165
+ {
166
+ LogWarning(e.Message);
167
+ }
168
+ finally
169
+ {
170
+ EditorUtility.ClearProgressBar();
171
+ }
172
+ }
173
+
174
+ private string KeyValueToText(SerializedProperty items)
175
+ {
176
+ StringBuilder sb = new StringBuilder();
177
+ for (int i = 0; i < items.arraySize; i++)
178
+ {
179
+ SerializedProperty c = items.GetArrayElementAtIndex(i);
180
+ sb.AppendLine($"{c.FindPropertyRelative("key").stringValue}\t{c.FindPropertyRelative("value").stringValue}");
181
+ }
182
+ return sb.ToString();
183
+ }
184
+
185
+ private void ShowError(string error)
186
+ {
187
+ EditorUtility.ClearProgressBar();
188
+ EditorUtility.DisplayDialog("Error", error, "OK");
189
+ }
190
+ }
191
+ }
@@ -0,0 +1,11 @@
1
+ fileFormatVersion: 2
2
+ guid: cc3262a8477b7444e8ba53e7174756f6
3
+ MonoImporter:
4
+ externalObjects: {}
5
+ serializedVersion: 2
6
+ defaultReferences: []
7
+ executionOrder: 0
8
+ icon: {instanceID: 0}
9
+ userData:
10
+ assetBundleName:
11
+ assetBundleVariant:
@@ -0,0 +1,151 @@
1
+ using System.Collections.Generic;
2
+ using UnityEditor;
3
+ using UnityEngine;
4
+ using System.IO;
5
+ using System.Linq;
6
+ using System;
7
+ using System.Text.RegularExpressions;
8
+ using Amanotes.Core.Internal;
9
+ using Amanotes.Editor;
10
+
11
+ namespace Amanotes.Core
12
+ {
13
+ internal class MatchSDKVersion
14
+ {
15
+ private static string defineVer = "#define VER_";
16
+ private static string comment = "//";
17
+
18
+ private static Dictionary<string, string> sdkToClassMap = new Dictionary<string, string>
19
+ {
20
+ { "FirebaseAnalytics", "FirebaseAnalyticsAdapter" },
21
+ { "FirebaseRemoteConfig", "FirebaseRemoteConfigAdapter" },
22
+ { "appsflyer-unity-plugin", "AppsFlyerAdapter" },
23
+ { "IronSource_IntegrationManager", "IronSourceAdapter" },
24
+ { "Adjust", "AdjustAdapter" },
25
+ { "Purchases", "RevenueCatAdapter" }
26
+ };
27
+
28
+ private static FileInfo[] files = null;
29
+
30
+ [InitializeOnLoadMethod]
31
+ private static void Initialize()
32
+ {
33
+ AssetDatabase.importPackageCompleted += UpdateAdapter;
34
+ }
35
+ private static void UncommentDefineAtLine(string filePath, int lineIndex)
36
+ {
37
+ string[] lines = File.ReadAllLines(filePath);
38
+
39
+ for (int i = 0; i < lines.Length; i++)
40
+ {
41
+ if (i == lineIndex)
42
+ {
43
+ lines[i] = lines[i].TrimStart(new[] { '/', ' ' });
44
+ }
45
+ else if (Regex.IsMatch(lines[i], @"^#define\s+"))
46
+ {
47
+ lines[i] = "//" + lines[i];
48
+ }
49
+ }
50
+
51
+ File.WriteAllLines(filePath, lines);
52
+ }
53
+
54
+ private static KeyValuePair<int, SemVer> FindNearestLowerVersion(SemVer inputVersion, Dictionary<int, SemVer> defineLines)
55
+ {
56
+ KeyValuePair<int, SemVer> versionLessAndNearest = default;
57
+ SemVer bestMatch = SemVer.ZERO;
58
+
59
+ foreach (var kvp in defineLines)
60
+ {
61
+ if(inputVersion.CompareTo(kvp.Value) < 0)
62
+ continue;
63
+ if(kvp.Value.CompareTo(bestMatch) <= 0)
64
+ continue;
65
+
66
+ bestMatch = kvp.Value;
67
+ versionLessAndNearest = kvp;
68
+ }
69
+
70
+ return versionLessAndNearest;
71
+ }
72
+
73
+ private static Dictionary<int, SemVer> GetSemVersDefine(string code)
74
+ {
75
+ Dictionary<int, SemVer> defineLines = new Dictionary<int, SemVer>();
76
+
77
+ string[] lines = code.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None);
78
+ for (int i = 0; i < lines.Length; i++)
79
+ {
80
+ string line = lines[i].Trim();
81
+
82
+ if (Regex.IsMatch(line, @"^(\/\/\s*)?#define\s+"))
83
+ {
84
+ defineLines.Add(i, new SemVer(GetVersionNumber(line)));
85
+ }
86
+ }
87
+
88
+ return defineLines;
89
+ }
90
+
91
+ private static string GetVersionNumber(string defineString)
92
+ {
93
+ string pattern = @"VER_(\d+)_(\d+)_(\d+)";
94
+
95
+ Match match = Regex.Match(defineString, pattern);
96
+
97
+ if (match.Success)
98
+ {
99
+ string major = match.Groups[1].Value;
100
+ string minor = match.Groups[2].Value;
101
+ string patch = match.Groups[3].Value;
102
+ string versionNumber = $"{major}.{minor}.{patch}";
103
+
104
+ return versionNumber;
105
+ }
106
+
107
+ return string.Empty;
108
+ }
109
+
110
+ private static void UpdateAdapter(string packageName)
111
+ {
112
+ if (files == null)
113
+ {
114
+ string dataPath = Path.Combine(Application.dataPath, "AmaGDK/Adapters");
115
+ if (!Directory.Exists(dataPath))
116
+ {
117
+ Logging.Log($"{dataPath} is not found");
118
+ return;
119
+ }
120
+ DirectoryInfo directory = new DirectoryInfo(dataPath);
121
+ files = directory.GetFiles("*Adapter.cs", SearchOption.AllDirectories);
122
+ }
123
+
124
+ if (sdkToClassMap.TryGetValue(GetSDKName(packageName), out string adapterClass))
125
+ {
126
+ var version = SDKStatus.Get(adapterClass.Replace("Adapter", "")).sdkVersion;
127
+ FileInfo file = files.FirstOrDefault(x => x.FullName.Contains($"{adapterClass}.cs"));
128
+
129
+ if (file != null)
130
+ {
131
+ Dictionary<int, SemVer> defineLines = GetSemVersDefine(File.ReadAllText(file.FullName));
132
+
133
+ KeyValuePair<int, SemVer> r = FindNearestLowerVersion(version, defineLines);
134
+
135
+ if (r.Value.isValid)
136
+ {
137
+ return;
138
+ }
139
+ UncommentDefineAtLine(file.FullName, r.Key);
140
+ }
141
+ }
142
+
143
+ AssetDatabase.Refresh();
144
+ }
145
+
146
+ private static string GetSDKName(string packageName)
147
+ {
148
+ return sdkToClassMap.Keys.FirstOrDefault(sdk => packageName.Contains(sdk));
149
+ }
150
+ }
151
+ }
@@ -0,0 +1,11 @@
1
+ fileFormatVersion: 2
2
+ guid: d5546420c6797492fb3cf9ea07b24f1a
3
+ MonoImporter:
4
+ externalObjects: {}
5
+ serializedVersion: 2
6
+ defaultReferences: []
7
+ executionOrder: 0
8
+ icon: {instanceID: 0}
9
+ userData:
10
+ assetBundleName:
11
+ assetBundleVariant:
@@ -24,7 +24,7 @@ namespace Amanotes.Editor
24
24
  }
25
25
  }
26
26
 
27
- [Serializable] internal class SDKStatus
27
+ [Serializable] public class SDKStatus
28
28
  {
29
29
 
30
30
  //
@@ -1,7 +1,10 @@
1
1
  using System;
2
2
  using System.Collections;
3
+ using System.Collections.Generic;
3
4
  using UnityEditor;
4
5
  using UnityEngine;
6
+ using UnityEngine.Networking;
7
+
5
8
  namespace Amanotes.Editor
6
9
  {
7
10
  internal static class Utils
@@ -31,4 +34,53 @@ namespace Amanotes.Editor
31
34
  EditorApplication.update += closureCallback;
32
35
  }
33
36
  }
37
+
38
+ internal static class WebRequest
39
+ {
40
+ internal static void Get(string url, Dictionary<string, string> headers = null, Action<float> onProgress = null, Action<string> onSuccess = null, Action<string> onError = null)
41
+ {
42
+ GetCoroutine(url, headers, onProgress, onSuccess, onError).StartEditorCoroutine();
43
+ }
44
+
45
+ private static IEnumerator GetCoroutine(string url, Dictionary<string, string> headers = null, Action<float> onProgress = null, Action<string> onSuccess = null, Action<string> onError = null)
46
+ {
47
+ using (var request = UnityWebRequest.Get(url))
48
+ {
49
+ // Add headers to the request
50
+ if (headers != null)
51
+ {
52
+ foreach (var header in headers)
53
+ {
54
+ request.SetRequestHeader(header.Key, header.Value);
55
+ }
56
+ }
57
+
58
+ // Send the request
59
+ request.timeout = 60;
60
+ yield return request.SendWebRequest();
61
+
62
+ while (request.isDone == false)
63
+ {
64
+ onProgress?.Invoke(request.downloadProgress);
65
+ yield return null;
66
+ }
67
+
68
+ // Check for errors
69
+ #pragma warning disable CS0618
70
+ if (request.isNetworkError || request.isHttpError)
71
+ #pragma warning restore CS0618
72
+ {
73
+ Debug.LogError("Error: " + request.error);
74
+ onError?.Invoke(request.error);
75
+ }
76
+ else
77
+ {
78
+ // Process the response
79
+ string responseText = request.downloadHandler.text;
80
+ onSuccess?.Invoke(responseText);
81
+ }
82
+ }
83
+
84
+ }
85
+ }
34
86
  }
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -336,6 +336,7 @@ namespace Amanotes.Core
336
336
  public static string IpAddress => User.amaPassport.device.ipAddress;
337
337
  public static string Country => User.amaPassport.device.country;
338
338
  public static string DeviceUniqueId => User.amaPassport.device.deviceUniqueId;
339
+ public static string AppsflyerId => User.amaPassport.device.appsflyerId;
339
340
 
340
341
  internal static void Init()
341
342
  {
@@ -301,7 +301,8 @@ namespace Amanotes.Core
301
301
  internal static void ProcessEventQueue()
302
302
  {
303
303
  if (eventQueue.Count <= 0) return;
304
- bool showAnalyticsLog = Config.common.showAnalyticsLog;
304
+ SDKConfig common = Config.common;
305
+ bool showAnalyticsLog = common.showAnalyticsLog;
305
306
  sessionStat.ClearLastFrameEventInfo();
306
307
 
307
308
  while (eventQueue.Count > 0)
@@ -317,9 +318,11 @@ namespace Amanotes.Core
317
318
  }
318
319
 
319
320
  string eventNameToSend = GetEventNameToSend(eventData.eventName, countInSession, totalCount);
320
- if (Config.common.normalizeEventName) NormalizeEventName(ref eventNameToSend);
321
+ if (common.normalizeEventName) NormalizeEventName(ref eventNameToSend);
321
322
 
322
- if (showAnalyticsLog) Debug.Log($"AmaGDK | Event <{eventNameToSend}> (in session: {countInSession}, total: {totalCount})\n{JsonUtils.DictionaryToJson(eventData.parameters, true)}");
323
+ if (showAnalyticsLog) Debug.Log($"AmaGDK | Event <{eventNameToSend}> (in session: {countInSession}, total: {totalCount})\n{JsonUtils.DictionaryToJson(eventData.parameters, true)}");
324
+
325
+ common.quality.CheckEventQuality(eventData.eventName, eventData.parameters);
323
326
 
324
327
  var inUseAdapterIDs = new List<string>();
325
328
  foreach (AdapterContext m in listAdapters)
@@ -731,12 +734,28 @@ namespace Amanotes.Core
731
734
 
732
735
  namespace Amanotes.Core.Internal
733
736
  {
737
+ [Serializable]
738
+ public class AnalyticQualityConfig
739
+ {
740
+ public bool enable = false;
741
+ public AnalyticQualityAsset qualityAsset;
742
+
743
+ public void CheckEventQuality(string eventName, Dictionary<string, object> parameters)
744
+ {
745
+ if (enable && qualityAsset != null)
746
+ {
747
+ qualityAsset.CheckEventQuality(eventName, parameters);
748
+ }
749
+ }
750
+ }
751
+
734
752
  public partial class SDKConfig
735
753
  {
736
754
  public bool showAnalyticsLog = true;
737
755
  public bool normalizeEventName = true;
738
756
  public bool checkMigrationIntegrity = true;
739
757
  public bool enableEventStat;
758
+ public AnalyticQualityConfig quality;
740
759
  }
741
760
 
742
761
  public interface IAnalyticAdapter