com.amanotes.gdk 0.2.80 → 0.2.81-a2
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 +9 -0
- package/Editor/AmaGDKEditor.cs +22 -9
- package/Editor/Extra/GDKCIBuildCommand.cs +46 -20
- package/Editor/Extra/GDKPostBuildAsset.cs +376 -0
- package/Editor/Extra/GDKPostBuildAsset.cs.meta +11 -0
- package/Editor/Extra/SDKVersionTracking.cs +2 -1
- package/Runtime/Ad/AmaGDK.Ads.cs +1 -1
- package/Runtime/AmaGDK.Analytics.cs +9 -3
- package/Runtime/AmaGDK.Consent.cs +2 -2
- package/Runtime/AmaGDK.IAP.cs +1 -1
- package/Runtime/AmaGDK.UserProfile.cs +2 -2
- package/Runtime/AmaGDK.cs +7 -4
- package/Runtime/Internal/AmaGDK.Internal.cs +12 -4
- package/Runtime/Internal/AmaGDK.Utils.cs +4 -228
- package/Runtime/Internal/ForceQuitMonitor.cs +1 -1
- package/Runtime/Utils/GDKFileUtils.cs +246 -0
- package/Runtime/Utils/GDKFileUtils.cs.meta +3 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.2.81-a2] - 2024-11-21
|
|
4
|
+
- [Dev] Add GDKPostBuild for iOS
|
|
5
|
+
- [Dev] Improve GDK editor experience before config asset imported
|
|
6
|
+
- [Dev] Analytics save file in async
|
|
7
|
+
- [Dev] Move GDKFileUtils to a separated file
|
|
8
|
+
- [Dev] Update game ops model
|
|
9
|
+
- [Dev] Add ABLab
|
|
10
|
+
- [Dev] Move imported GDK Adapter from RawData to Modules
|
|
11
|
+
|
|
3
12
|
## [0.2.80] - 2024-11-13
|
|
4
13
|
- [Dev] Don't use obsolete functions
|
|
5
14
|
- [Dev] Add CrashlyticHook
|
package/Editor/AmaGDKEditor.cs
CHANGED
|
@@ -57,20 +57,21 @@ namespace Amanotes.Editor
|
|
|
57
57
|
|
|
58
58
|
public void OnEnable()
|
|
59
59
|
{
|
|
60
|
+
if (sdk == target) return;
|
|
61
|
+
|
|
60
62
|
sdk = (AmaGDK)target;
|
|
61
63
|
if (sdk != null) sdk.transform.hideFlags = HideFlags.HideInInspector;
|
|
62
|
-
|
|
63
64
|
SDKStatus.ClearCache();
|
|
64
65
|
RefreshConfigStatus();
|
|
65
|
-
|
|
66
|
+
RefreshListAdapters();
|
|
66
67
|
}
|
|
67
68
|
|
|
68
69
|
internal enum ConfigAssetStatus
|
|
69
70
|
{
|
|
70
71
|
None,
|
|
71
72
|
ScriptNotFound,
|
|
73
|
+
ImportConfigPackage,
|
|
72
74
|
AssetNotFound,
|
|
73
|
-
AssetIsInvalid,
|
|
74
75
|
AssetOk
|
|
75
76
|
}
|
|
76
77
|
|
|
@@ -78,6 +79,8 @@ namespace Amanotes.Editor
|
|
|
78
79
|
|
|
79
80
|
void RefreshConfigStatus()
|
|
80
81
|
{
|
|
82
|
+
AmaGDK._hasLoadConfig = false;
|
|
83
|
+
|
|
81
84
|
string[] scriptGUIDs = AssetDatabase.FindAssets("t:MonoScript AmaGDKConfigAsset");
|
|
82
85
|
if (scriptGUIDs.Length == 0)
|
|
83
86
|
{
|
|
@@ -85,14 +88,13 @@ namespace Amanotes.Editor
|
|
|
85
88
|
return;
|
|
86
89
|
}
|
|
87
90
|
|
|
88
|
-
string[] assetGUIDs = AssetDatabase.FindAssets("t:
|
|
91
|
+
string[] assetGUIDs = AssetDatabase.FindAssets("t:AmaGDKConfigAsset");
|
|
89
92
|
if (assetGUIDs.Length == 0)
|
|
90
93
|
{
|
|
91
94
|
cfgStatus = ConfigAssetStatus.AssetNotFound;
|
|
92
95
|
return;
|
|
93
96
|
}
|
|
94
97
|
|
|
95
|
-
cfgStatus = configAsset != null ? ConfigAssetStatus.AssetOk : ConfigAssetStatus.AssetIsInvalid;
|
|
96
98
|
if (cfgStatus == ConfigAssetStatus.AssetOk) adapterScanned = false;
|
|
97
99
|
}
|
|
98
100
|
|
|
@@ -261,22 +263,30 @@ namespace Amanotes.Editor
|
|
|
261
263
|
void DrawGUI_GDKConfig()
|
|
262
264
|
{
|
|
263
265
|
if (cfgStatus == ConfigAssetStatus.None) RefreshConfigStatus();
|
|
264
|
-
if (cfgStatus == ConfigAssetStatus.ScriptNotFound
|
|
265
|
-
|| cfgStatus == ConfigAssetStatus.AssetIsInvalid)
|
|
266
|
+
if (cfgStatus == ConfigAssetStatus.ScriptNotFound)
|
|
266
267
|
{
|
|
267
|
-
|
|
268
|
+
cfgStatus = ConfigAssetStatus.ImportConfigPackage;
|
|
269
|
+
AmaGDK._hasLoadConfig = false;
|
|
268
270
|
AssetDatabase.ImportPackage(Res.AMAGDK_CONFIG_PACKAGE, false);
|
|
269
271
|
return;
|
|
270
272
|
}
|
|
271
273
|
|
|
274
|
+
if (cfgStatus == ConfigAssetStatus.ImportConfigPackage)
|
|
275
|
+
{
|
|
276
|
+
EditorGUILayout.HelpBox("Importing AmaGDKConfig package...", MessageType.Info);
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
|
|
272
280
|
if (cfgStatus == ConfigAssetStatus.AssetNotFound)
|
|
273
281
|
{
|
|
274
|
-
EditorGUILayout.HelpBox("[Warning] <Resources/AmaGDKConfig.asset> NOT FOUND!\nYou need to create one to control all the adapter's configurations!", MessageType.Warning);
|
|
282
|
+
EditorGUILayout.HelpBox("[Warning] <Resources/AmaGDKConfig.asset> NOT FOUND or INVALID!\nYou need to create one to control all the adapter's configurations!", MessageType.Warning);
|
|
275
283
|
GUILayout.BeginHorizontal();
|
|
276
284
|
{
|
|
277
285
|
if (AmaGUI.BigButton("CREATE", 40f, BLUE))
|
|
278
286
|
{
|
|
279
287
|
CreateGDKConfig();
|
|
288
|
+
|
|
289
|
+
cfgStatus = ConfigAssetStatus.None;
|
|
280
290
|
RefreshConfigStatus();
|
|
281
291
|
}
|
|
282
292
|
|
|
@@ -291,6 +301,9 @@ namespace Amanotes.Editor
|
|
|
291
301
|
|
|
292
302
|
if (configAsset == null)
|
|
293
303
|
{
|
|
304
|
+
AmaGDK._hasLoadConfig = false;
|
|
305
|
+
Resources.UnloadUnusedAssets();
|
|
306
|
+
|
|
294
307
|
Debug.LogWarning("Have you just deleted AmaGDKConfig.asset?" + cfgStatus);
|
|
295
308
|
cfgStatus = ConfigAssetStatus.None;
|
|
296
309
|
Repaint();
|
|
@@ -24,32 +24,58 @@ namespace Amanotes.Core
|
|
|
24
24
|
private const string VERSION_NUMBER_VAR = "VERSION_NUMBER_VAR";
|
|
25
25
|
private const string VERSION_iOS = "VERSION_BUILD_VAR";
|
|
26
26
|
|
|
27
|
-
public static void InstallPod(EventHandler processExit)
|
|
27
|
+
public static void InstallPod(EventHandler processExit, string buildPath = null)
|
|
28
28
|
{
|
|
29
29
|
try
|
|
30
30
|
{
|
|
31
|
-
|
|
31
|
+
var arguments = $"-c \"/usr/local/bin/pod install --project-directory={buildPath}\"";
|
|
32
|
+
if (Application.isBatchMode && TryGetEnv("CI_SCRIPT_DIR", out string scriptDir))
|
|
32
33
|
{
|
|
33
|
-
|
|
34
|
-
{
|
|
35
|
-
FileName = "/bin/bash",
|
|
36
|
-
Arguments = $"{scriptDir}/utils.sh pod-install",
|
|
37
|
-
CreateNoWindow = true
|
|
38
|
-
};
|
|
39
|
-
var proc = new Process
|
|
40
|
-
{
|
|
41
|
-
StartInfo = startInfo,
|
|
42
|
-
EnableRaisingEvents = true
|
|
43
|
-
};
|
|
44
|
-
proc.Exited += processExit;
|
|
45
|
-
proc.Start();
|
|
46
|
-
proc.WaitForExit();
|
|
34
|
+
arguments = $"{scriptDir}/utils.sh pod-install";
|
|
47
35
|
}
|
|
48
|
-
|
|
36
|
+
|
|
37
|
+
// Configure process start info
|
|
38
|
+
var startInfo = new ProcessStartInfo
|
|
49
39
|
{
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
40
|
+
FileName = "/bin/zsh",
|
|
41
|
+
Arguments = arguments,
|
|
42
|
+
CreateNoWindow = false,
|
|
43
|
+
RedirectStandardOutput = true,
|
|
44
|
+
RedirectStandardError = true,
|
|
45
|
+
UseShellExecute = false
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
var proc = new Process
|
|
49
|
+
{
|
|
50
|
+
StartInfo = startInfo,
|
|
51
|
+
EnableRaisingEvents = true
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
// Attach event handlers
|
|
55
|
+
proc.OutputDataReceived += (sender, args) =>
|
|
56
|
+
{
|
|
57
|
+
if (args.Data == null) return; // End of the stream
|
|
58
|
+
Debug.Log(args.Data);
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
// proc.ErrorDataReceived += (sender, args) =>
|
|
62
|
+
// {
|
|
63
|
+
// if (args.Data == null) return; // End of the stream
|
|
64
|
+
// Debug.LogError(args.Data);
|
|
65
|
+
// };
|
|
66
|
+
|
|
67
|
+
proc.Exited += processExit;
|
|
68
|
+
|
|
69
|
+
// Start the process
|
|
70
|
+
proc.Start();
|
|
71
|
+
proc.BeginOutputReadLine();
|
|
72
|
+
proc.BeginErrorReadLine();
|
|
73
|
+
proc.WaitForExit();
|
|
74
|
+
|
|
75
|
+
// Log exit code
|
|
76
|
+
// Debug.LogWarning("Process exited with code: " + proc.ExitCode);
|
|
77
|
+
}
|
|
78
|
+
catch (Exception e)
|
|
53
79
|
{
|
|
54
80
|
Debug.LogError(e);
|
|
55
81
|
}
|
|
@@ -0,0 +1,376 @@
|
|
|
1
|
+
using UnityEngine;
|
|
2
|
+
using UnityEditor;
|
|
3
|
+
|
|
4
|
+
using System.IO;
|
|
5
|
+
using System.Collections.Generic;
|
|
6
|
+
using UnityEditor.Callbacks;
|
|
7
|
+
|
|
8
|
+
#if UNITY_IOS
|
|
9
|
+
using Amanotes.Core;
|
|
10
|
+
using UnityEditor.iOS.Xcode;
|
|
11
|
+
using UnityEditor.iOS.Xcode.Extensions;
|
|
12
|
+
#endif
|
|
13
|
+
|
|
14
|
+
namespace Amanotes.Editor
|
|
15
|
+
{
|
|
16
|
+
[CreateAssetMenu(fileName = "GDKPostBuildAsset", menuName = "Ama GDK/GDKPostBuildAsset", order = 1)]
|
|
17
|
+
public class GDKPostBuildAsset : ScriptableObject
|
|
18
|
+
{
|
|
19
|
+
[System.Serializable]
|
|
20
|
+
public class Framework
|
|
21
|
+
{
|
|
22
|
+
public string name;
|
|
23
|
+
public bool enable;
|
|
24
|
+
public bool isWeak;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
[System.Serializable]
|
|
28
|
+
public class PodFramework
|
|
29
|
+
{
|
|
30
|
+
public string relativePath; // Only the framework name, e.g., "AppLovinSDK"
|
|
31
|
+
public bool enable;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
[System.Serializable]
|
|
35
|
+
public class PlistKey
|
|
36
|
+
{
|
|
37
|
+
public string key;
|
|
38
|
+
public string value;
|
|
39
|
+
public bool isString;
|
|
40
|
+
public bool enable;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
[System.Serializable]
|
|
44
|
+
public class BuildProperty
|
|
45
|
+
{
|
|
46
|
+
public string key;
|
|
47
|
+
public string value;
|
|
48
|
+
public bool enable;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
[System.Serializable]
|
|
52
|
+
public class Capability
|
|
53
|
+
{
|
|
54
|
+
public string type;
|
|
55
|
+
public string entitlementFile;
|
|
56
|
+
public bool enable;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
[Header("Frameworks to Add")]
|
|
60
|
+
public List<Framework> frameworks = new List<Framework>
|
|
61
|
+
{
|
|
62
|
+
new Framework { name = "iAd.framework", enable = true, isWeak = false },
|
|
63
|
+
new Framework { name = "AdSupport.framework", enable = true, isWeak = false },
|
|
64
|
+
new Framework { name = "CoreData.framework", enable = true, isWeak = false },
|
|
65
|
+
new Framework { name = "Security.framework", enable = true, isWeak = false },
|
|
66
|
+
new Framework { name = "UserNotifications.framework", enable = true, isWeak = false },
|
|
67
|
+
new Framework { name = "UIKit.framework", enable = true, isWeak = false },
|
|
68
|
+
new Framework { name = "WebKit.framework", enable = true, isWeak = false },
|
|
69
|
+
new Framework { name = "CoreGraphics.framework", enable = true, isWeak = false },
|
|
70
|
+
new Framework { name = "SystemConfiguration.framework", enable = true, isWeak = false },
|
|
71
|
+
new Framework { name = "MobileCoreServices.framework", enable = true, isWeak = false },
|
|
72
|
+
new Framework { name = "AppTrackingTransparency.framework", enable = true, isWeak = false }
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
[Header("Pod Frameworks to Add")]
|
|
76
|
+
public List<PodFramework> podFrameworks = new List<PodFramework>
|
|
77
|
+
{
|
|
78
|
+
new PodFramework { relativePath = "AppLovinSDK", enable = true },
|
|
79
|
+
new PodFramework { relativePath = "InMobiSDK", enable = true }
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
[Header("Info.plist Keys to Add")]
|
|
83
|
+
public List<PlistKey> plistKeys = new List<PlistKey>
|
|
84
|
+
{
|
|
85
|
+
new PlistKey { key = "NSCalendarsUsageDescription", value = "App requires calendar access.", isString = true, enable = true },
|
|
86
|
+
new PlistKey { key = "NSCameraUsageDescription", value = "App requires camera access.", isString = true, enable = true },
|
|
87
|
+
new PlistKey { key = "NSPhotoLibraryUsageDescription", value = "App requires photo library access.", isString = true, enable = true },
|
|
88
|
+
new PlistKey { key = "NSMotionUsageDescription", value = "App requires motion control.", isString = true, enable = true },
|
|
89
|
+
new PlistKey { key = "NSLocationWhenInUseUsageDescription", value = "App requires location access.", isString = true, enable = true },
|
|
90
|
+
new PlistKey { key = "NSUserTrackingUsageDescription", value = "App requires user tracking permission.", isString = true, enable = true }
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
[Header("Build Properties to Set")]
|
|
94
|
+
public List<BuildProperty> buildProperties = new List<BuildProperty>
|
|
95
|
+
{
|
|
96
|
+
new BuildProperty { key = "ENABLE_BITCODE", value = "NO", enable = true },
|
|
97
|
+
new BuildProperty { key = "VERSIONING_SYSTEM", value = "apple-generic", enable = true },
|
|
98
|
+
new BuildProperty { key = "CURRENT_PROJECT_VERSION", value = "1", enable = true },
|
|
99
|
+
new BuildProperty { key = "CODE_SIGN_STYLE", value = "Manual", enable = true }
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
[Header("Capabilities to Enable")]
|
|
103
|
+
public List<Capability> capabilities = new List<Capability>
|
|
104
|
+
{
|
|
105
|
+
new Capability { type = "com.apple.Push", entitlementFile = "amanotes.entitlements", enable = true },
|
|
106
|
+
new Capability { type = "com.apple.InAppPurchase", entitlementFile = "", enable = true },
|
|
107
|
+
new Capability { type = "com.apple.BackgroundModes", entitlementFile = "", enable = true }
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
public string lastBuildPath;
|
|
111
|
+
|
|
112
|
+
#if UNITY_IOS
|
|
113
|
+
private const string PLIST_FILE = "Info.plist";
|
|
114
|
+
private const string EXIST_ON_SUSPEND_KEY = "UIApplicationExitsOnSuspend";
|
|
115
|
+
|
|
116
|
+
public void ExecutePostBuild(string pathToBuildProject)
|
|
117
|
+
{
|
|
118
|
+
lastBuildPath = pathToBuildProject;
|
|
119
|
+
|
|
120
|
+
if (string.IsNullOrEmpty(pathToBuildProject))
|
|
121
|
+
{
|
|
122
|
+
Debug.LogError("Path to build project is null or empty.");
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
string projectPath = PBXProject.GetPBXProjectPath(pathToBuildProject);
|
|
127
|
+
if (!File.Exists(projectPath))
|
|
128
|
+
{
|
|
129
|
+
Debug.LogError($"Xcode project file not found at {projectPath}");
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
var proj = new PBXProject();
|
|
134
|
+
proj.ReadFromFile(projectPath);
|
|
135
|
+
|
|
136
|
+
#if UNITY_2020_1_OR_NEWER
|
|
137
|
+
string frameworkTargetGuid = proj.GetUnityFrameworkTargetGuid();
|
|
138
|
+
string mainTargetGuid = proj.GetUnityMainTargetGuid();
|
|
139
|
+
#else
|
|
140
|
+
string frameworkTargetGuid = proj.TargetGuidByName("UnityFramework");
|
|
141
|
+
string mainTargetGuid = proj.TargetGuidByName("Unity-iPhone");
|
|
142
|
+
#endif
|
|
143
|
+
|
|
144
|
+
// Remove deprecated Info.plist keys
|
|
145
|
+
RemoveDeprecatedInfoPListKeys(pathToBuildProject);
|
|
146
|
+
if (string.IsNullOrEmpty(mainTargetGuid))
|
|
147
|
+
{
|
|
148
|
+
Debug.LogError("Main target GUID is null or empty.");
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
SetBuildProperties(proj, mainTargetGuid);
|
|
153
|
+
AddCapabilities(proj, pathToBuildProject, mainTargetGuid);
|
|
154
|
+
AddFrameworks(proj, mainTargetGuid);
|
|
155
|
+
|
|
156
|
+
GDKCIBuildCommand.InstallPod((sender, e) =>
|
|
157
|
+
{
|
|
158
|
+
AddPodFrameworks(proj, pathToBuildProject, mainTargetGuid);
|
|
159
|
+
ModifyInfoPlist(pathToBuildProject);
|
|
160
|
+
proj.WriteToFile(projectPath);
|
|
161
|
+
}, pathToBuildProject);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
private void RemoveDeprecatedInfoPListKeys(string pathToBuildProject)
|
|
165
|
+
{
|
|
166
|
+
string plistPath = Path.Combine(pathToBuildProject, PLIST_FILE);
|
|
167
|
+
PlistDocument plist = new PlistDocument();
|
|
168
|
+
plist.ReadFromString(File.ReadAllText(plistPath));
|
|
169
|
+
|
|
170
|
+
PlistElementDict rootDict = plist.root;
|
|
171
|
+
|
|
172
|
+
if (rootDict.values.ContainsKey(EXIST_ON_SUSPEND_KEY))
|
|
173
|
+
{
|
|
174
|
+
Debug.Log($"Removing deprecated key \"{EXIST_ON_SUSPEND_KEY}\" from \"{PLIST_FILE}\".");
|
|
175
|
+
rootDict.values.Remove(EXIST_ON_SUSPEND_KEY);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
File.WriteAllText(plistPath, plist.WriteToString());
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
private void SetBuildProperties(PBXProject proj, string targetGuid)
|
|
182
|
+
{
|
|
183
|
+
foreach (var property in buildProperties)
|
|
184
|
+
{
|
|
185
|
+
if (!property.enable) continue;
|
|
186
|
+
proj.SetBuildProperty(targetGuid, property.key, property.value);
|
|
187
|
+
Debug.Log($"Set build property: {property.key} = {property.value}");
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// Enable Capabilities
|
|
192
|
+
private void AddCapabilities(PBXProject proj, string pathToBuildProject, string targetGuid)
|
|
193
|
+
{
|
|
194
|
+
foreach (var capability in capabilities)
|
|
195
|
+
{
|
|
196
|
+
if (!capability.enable) continue;
|
|
197
|
+
|
|
198
|
+
var pbxCapabilityType = PBXCapabilityType.StringToPBXCapabilityType(capability.type);
|
|
199
|
+
if (pbxCapabilityType == null)
|
|
200
|
+
{
|
|
201
|
+
Debug.LogError($"Unknown capability type: {capability.type}");
|
|
202
|
+
continue;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
if (!string.IsNullOrEmpty(capability.entitlementFile))
|
|
206
|
+
{
|
|
207
|
+
string entitlementsPath = Path.Combine(pathToBuildProject, capability.entitlementFile);
|
|
208
|
+
if (!File.Exists(entitlementsPath))
|
|
209
|
+
{
|
|
210
|
+
Debug.LogError($"Entitlements file not found: {entitlementsPath}");
|
|
211
|
+
continue;
|
|
212
|
+
}
|
|
213
|
+
proj.AddCapability(targetGuid, pbxCapabilityType, entitlementsPath);
|
|
214
|
+
Debug.Log($"Added capability: {pbxCapabilityType.id} with entitlements: {entitlementsPath}");
|
|
215
|
+
}
|
|
216
|
+
else
|
|
217
|
+
{
|
|
218
|
+
proj.AddCapability(targetGuid, pbxCapabilityType);
|
|
219
|
+
Debug.Log($"Added capability: {pbxCapabilityType.id}");
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
private void AddFrameworks(PBXProject proj, string targetGuid)
|
|
225
|
+
{
|
|
226
|
+
foreach (var framework in frameworks)
|
|
227
|
+
{
|
|
228
|
+
if (!framework.enable) continue;
|
|
229
|
+
proj.AddFrameworkToProject(targetGuid, framework.name, framework.isWeak);
|
|
230
|
+
Debug.Log($"Added framework: {framework.name} (Weak: {framework.isWeak})");
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
private void AddPodFrameworks(PBXProject proj, string pathToBuildProject, string targetGuid)
|
|
235
|
+
{
|
|
236
|
+
string podsDirectory = Path.Combine(pathToBuildProject, "Pods");
|
|
237
|
+
if (!Directory.Exists(podsDirectory))
|
|
238
|
+
{
|
|
239
|
+
Debug.LogError($"Pods directory not found. Ensure pod install has completed successfully.");
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
foreach (var podFramework in podFrameworks)
|
|
244
|
+
{
|
|
245
|
+
if (!podFramework.enable) continue;
|
|
246
|
+
|
|
247
|
+
string frameworkPath = SearchForPodFramework(pathToBuildProject, podFramework.relativePath);
|
|
248
|
+
if (string.IsNullOrEmpty(frameworkPath))
|
|
249
|
+
{
|
|
250
|
+
Debug.LogError($"Failed to find Pod framework for: {podFramework.relativePath}");
|
|
251
|
+
continue;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
string fileGuid = proj.AddFile(frameworkPath, frameworkPath, PBXSourceTree.Source);
|
|
255
|
+
if (string.IsNullOrEmpty(fileGuid))
|
|
256
|
+
{
|
|
257
|
+
Debug.LogError($"Failed to add Pod framework: {frameworkPath}");
|
|
258
|
+
continue;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
proj.AddFileToEmbedFrameworks(targetGuid, fileGuid);
|
|
262
|
+
|
|
263
|
+
// Set CODE_SIGN_ON_COPY for Debug and Release configurations
|
|
264
|
+
// string debugConfig = proj.BuildConfigByName(targetGuid, "Debug");
|
|
265
|
+
// string releaseConfig = proj.BuildConfigByName(targetGuid, "Release");
|
|
266
|
+
//
|
|
267
|
+
// if (!string.IsNullOrEmpty(debugConfig))
|
|
268
|
+
// {
|
|
269
|
+
// proj.SetBuildProperty(debugConfig, "CODE_SIGN_ON_COPY", "YES");
|
|
270
|
+
// }
|
|
271
|
+
//
|
|
272
|
+
// if (!string.IsNullOrEmpty(releaseConfig))
|
|
273
|
+
// {
|
|
274
|
+
// proj.SetBuildProperty(releaseConfig, "CODE_SIGN_ON_COPY", "YES");
|
|
275
|
+
// }
|
|
276
|
+
|
|
277
|
+
Debug.Log($"Added Pod framework to Embed Frameworks: {frameworkPath}");
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
private void ModifyInfoPlist(string pathToBuildProject)
|
|
282
|
+
{
|
|
283
|
+
string plistPath = Path.Combine(pathToBuildProject, PLIST_FILE);
|
|
284
|
+
if (!File.Exists(plistPath))
|
|
285
|
+
{
|
|
286
|
+
Debug.LogError($"Info.plist file not found at {plistPath}");
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
var plist = new PlistDocument();
|
|
291
|
+
plist.ReadFromFile(plistPath);
|
|
292
|
+
var rootDict = plist.root;
|
|
293
|
+
|
|
294
|
+
foreach (var plistKey in plistKeys)
|
|
295
|
+
{
|
|
296
|
+
if (!plistKey.enable) continue;
|
|
297
|
+
|
|
298
|
+
if (plistKey.isString)
|
|
299
|
+
{
|
|
300
|
+
rootDict.SetString(plistKey.key, plistKey.value);
|
|
301
|
+
}
|
|
302
|
+
else if (bool.TryParse(plistKey.value, out bool boolValue))
|
|
303
|
+
{
|
|
304
|
+
rootDict.SetBoolean(plistKey.key, boolValue);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
Debug.Log($"Added/Updated Info.plist key: {plistKey.key}");
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
plist.WriteToFile(plistPath);
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
private string SearchForPodFramework(string projectPath, string podFrameworkName)
|
|
314
|
+
{
|
|
315
|
+
string podsDirectory = Path.Combine(projectPath, "Pods", podFrameworkName);
|
|
316
|
+
|
|
317
|
+
if (!Directory.Exists(podsDirectory))
|
|
318
|
+
{
|
|
319
|
+
Debug.LogError($"Pods directory not found for: {podFrameworkName}");
|
|
320
|
+
return null;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// Recursively search for directories named {POD_FRAMEWORK_NAME}.xcframework
|
|
324
|
+
string[] frameworkPaths = Directory.GetDirectories(podsDirectory, $"{podFrameworkName}.xcframework", SearchOption.AllDirectories);
|
|
325
|
+
|
|
326
|
+
if (frameworkPaths.Length > 0)
|
|
327
|
+
{
|
|
328
|
+
Debug.Log($"Found framework for {podFrameworkName}: {frameworkPaths[0]}");
|
|
329
|
+
return frameworkPaths[0];
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
Debug.LogError($"No .xcframework folder found for {podFrameworkName} in {podsDirectory}");
|
|
333
|
+
return null;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
[PostProcessBuild]
|
|
337
|
+
public static void OnPostprocessBuild(BuildTarget target, string pathToBuildProject)
|
|
338
|
+
{
|
|
339
|
+
if (target != BuildTarget.iOS) return;
|
|
340
|
+
|
|
341
|
+
GDKPostBuildAsset postBuildAsset = FindGDKPostBuildAsset();
|
|
342
|
+
if (postBuildAsset == null) return;
|
|
343
|
+
|
|
344
|
+
Debug.Log($"Post processing: {pathToBuildProject}");
|
|
345
|
+
postBuildAsset.ExecutePostBuild(pathToBuildProject);
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
[MenuItem("Window/AmaGDK/Postprocess Build iOS")]
|
|
349
|
+
public static void RunPostBuildIOS()
|
|
350
|
+
{
|
|
351
|
+
var buildAsset = FindGDKPostBuildAsset();
|
|
352
|
+
if (buildAsset == null) return;
|
|
353
|
+
|
|
354
|
+
if (string.IsNullOrEmpty(buildAsset.lastBuildPath))
|
|
355
|
+
{
|
|
356
|
+
buildAsset.lastBuildPath = Path.GetFullPath("../../_Build/XCode_PHB3_v2.13.3_b200611");
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
OnPostprocessBuild(BuildTarget.iOS, buildAsset.lastBuildPath);
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
public static GDKPostBuildAsset FindGDKPostBuildAsset()
|
|
363
|
+
{
|
|
364
|
+
string[] guids = AssetDatabase.FindAssets("t:GDKPostBuildAsset");
|
|
365
|
+
if (guids.Length == 0)
|
|
366
|
+
{
|
|
367
|
+
Debug.LogError("No GDKPostBuildAsset found in the project.");
|
|
368
|
+
return null;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
string path = AssetDatabase.GUIDToAssetPath(guids[0]);
|
|
372
|
+
return AssetDatabase.LoadAssetAtPath<GDKPostBuildAsset>(path);
|
|
373
|
+
}
|
|
374
|
+
#endif
|
|
375
|
+
}
|
|
376
|
+
}
|
|
@@ -270,7 +270,6 @@ namespace Amanotes.Editor
|
|
|
270
270
|
public static void OnPostProcessBuild(BuildTarget target, string pathToBuiltProject)
|
|
271
271
|
{
|
|
272
272
|
var rawData = _dicThirdPartyVersion
|
|
273
|
-
.Concat(_dicImportedGDKAdapter)
|
|
274
273
|
.Concat(_dicExtraVersion)
|
|
275
274
|
.Concat(_dicIronSourceAdapterVersion.ToDictionary(kvp => kvp.Key, kvp => (object)("IS_" + kvp.Value)))
|
|
276
275
|
.ToDictionary(x => x.Key, x => x.Value);
|
|
@@ -293,8 +292,10 @@ namespace Amanotes.Editor
|
|
|
293
292
|
{"BuildTime", GetBuildTime()},
|
|
294
293
|
{"AppId", PlayerSettings.applicationIdentifier },
|
|
295
294
|
{"Platform", platform},
|
|
295
|
+
{"Modules", _dicImportedGDKAdapter },
|
|
296
296
|
{"RawData", rawData }
|
|
297
297
|
};
|
|
298
|
+
|
|
298
299
|
string json = JsonUtils.DictionaryToJson(buildInfo, false, false);
|
|
299
300
|
Task.Run(()=>SendDataToAirTable(json));
|
|
300
301
|
}
|
package/Runtime/Ad/AmaGDK.Ads.cs
CHANGED
|
@@ -135,7 +135,7 @@ namespace Amanotes.Core
|
|
|
135
135
|
|
|
136
136
|
if (!localData._dirty) return;
|
|
137
137
|
localData._dirty = false;
|
|
138
|
-
localData.SaveJsonToFile();
|
|
138
|
+
localData.SaveJsonToFile(true); // immediately = true
|
|
139
139
|
}
|
|
140
140
|
|
|
141
141
|
public static IEventParamsBuilder LogFunnelEvent(string eventName, string signature = "")
|
|
@@ -314,7 +314,7 @@ namespace Amanotes.Core
|
|
|
314
314
|
internal static readonly GDKPool.Pool<EventParams> epPool = new GDKPool.Pool<EventParams>(1);
|
|
315
315
|
|
|
316
316
|
private static readonly Lazy<AnalyticsData> _localData = new Lazy<AnalyticsData>(
|
|
317
|
-
() => new AnalyticsData().
|
|
317
|
+
() => new AnalyticsData().ReloadDataFromLocal());
|
|
318
318
|
internal static AnalyticsData localData => _localData.Value;
|
|
319
319
|
|
|
320
320
|
internal static readonly Dictionary<string, string> reservedPrefixes = new Dictionary<string, string>()
|
|
@@ -800,6 +800,12 @@ namespace Amanotes.Core
|
|
|
800
800
|
return this;
|
|
801
801
|
}
|
|
802
802
|
|
|
803
|
+
public AnalyticsData ReloadDataFromLocal()
|
|
804
|
+
{
|
|
805
|
+
this.LoadJsonFromFile().BuildCache();
|
|
806
|
+
return this;
|
|
807
|
+
}
|
|
808
|
+
|
|
803
809
|
internal EventDetail GetEventDetail(string eventName, bool autoNew = false)
|
|
804
810
|
{
|
|
805
811
|
if (string.IsNullOrEmpty(eventName)) return null;
|
|
@@ -843,7 +849,7 @@ namespace Amanotes.Core
|
|
|
843
849
|
if (!Config.analytics.autoFlushEventDetail) return;
|
|
844
850
|
if (!_dirty) return;
|
|
845
851
|
_dirty = false;
|
|
846
|
-
this.SaveJsonToFile();
|
|
852
|
+
this.SaveJsonToFile(false);
|
|
847
853
|
}
|
|
848
854
|
|
|
849
855
|
internal void UpdateMigrationLog()
|
|
@@ -66,7 +66,7 @@ namespace Amanotes.Core
|
|
|
66
66
|
ConsentHook.ATTRequest(isAllowed =>
|
|
67
67
|
{
|
|
68
68
|
data.att = isAllowed ? Status.Allowed : Status.NotAllowed;
|
|
69
|
-
data.SaveJsonToFile();
|
|
69
|
+
data.SaveJsonToFile(false);
|
|
70
70
|
onComplete?.Invoke(allowedATT);
|
|
71
71
|
});
|
|
72
72
|
}
|
|
@@ -107,7 +107,7 @@ namespace Amanotes.Core
|
|
|
107
107
|
if (successful)
|
|
108
108
|
{
|
|
109
109
|
data.cmp = !IsRequired ? Status.NotRequired : Status.Allowed;
|
|
110
|
-
data.SaveJsonToFile();
|
|
110
|
+
data.SaveJsonToFile(false);
|
|
111
111
|
}
|
|
112
112
|
onComplete?.Invoke(checkedCMP);
|
|
113
113
|
});
|
package/Runtime/AmaGDK.IAP.cs
CHANGED
|
@@ -306,7 +306,7 @@ namespace Amanotes.Core
|
|
|
306
306
|
subscriptionExpiredDate = _subscriptionExpiredDate?.ToString(DATE_FORMAT);
|
|
307
307
|
_unsubscribedDate = Adapter.GetUnsubscribedDate();
|
|
308
308
|
unsubscribedDate = _unsubscribedDate?.ToString(DATE_FORMAT);
|
|
309
|
-
this.SaveJsonToFile();
|
|
309
|
+
this.SaveJsonToFile(false);
|
|
310
310
|
}
|
|
311
311
|
}
|
|
312
312
|
}
|
|
@@ -33,14 +33,14 @@ namespace Amanotes.Core
|
|
|
33
33
|
private bool _dirty = false;
|
|
34
34
|
private void Save()
|
|
35
35
|
{
|
|
36
|
-
this.SaveJsonToFile();
|
|
36
|
+
this.SaveJsonToFile(false);
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
private void SaveIfDirty()
|
|
40
40
|
{
|
|
41
41
|
if (!_dirty) return;
|
|
42
42
|
_dirty = false;
|
|
43
|
-
this.SaveJsonToFile();
|
|
43
|
+
this.SaveJsonToFile(false);
|
|
44
44
|
}
|
|
45
45
|
}
|
|
46
46
|
|
package/Runtime/AmaGDK.cs
CHANGED
|
@@ -27,10 +27,10 @@ namespace Amanotes.Core
|
|
|
27
27
|
{
|
|
28
28
|
public partial class AmaGDK : MonoBehaviour
|
|
29
29
|
{
|
|
30
|
-
public const string VERSION = "0.2.
|
|
30
|
+
public const string VERSION = "0.2.81-a2";
|
|
31
31
|
|
|
32
32
|
internal static Status _status = Status.None;
|
|
33
|
-
|
|
33
|
+
internal static ConfigAsset _config = null;
|
|
34
34
|
|
|
35
35
|
private static readonly Lazy<GDKGeoLocation> _geoLocation = new Lazy<GDKGeoLocation>(() => new GDKGeoLocation());
|
|
36
36
|
private static readonly Lazy<GDKServerTime> _serverTime = new Lazy<GDKServerTime>(() => new GDKServerTime());
|
|
@@ -41,7 +41,8 @@ namespace Amanotes.Core
|
|
|
41
41
|
internal static GDKServerTime ServerTime => _serverTime.Value;
|
|
42
42
|
private static ForceQuitMonitor ForceQuit => _forceQuit.Value;
|
|
43
43
|
|
|
44
|
-
internal static bool _allowInit = false;
|
|
44
|
+
[NonSerialized] internal static bool _allowInit = false;
|
|
45
|
+
[NonSerialized] internal static bool _hasLoadConfig = false;
|
|
45
46
|
|
|
46
47
|
public bool autoInit = true;
|
|
47
48
|
|
|
@@ -65,8 +66,10 @@ namespace Amanotes.Core
|
|
|
65
66
|
{
|
|
66
67
|
get
|
|
67
68
|
{
|
|
68
|
-
if (_config != null) return _config;
|
|
69
|
+
if (_config != null || _hasLoadConfig) return _config;
|
|
70
|
+
_hasLoadConfig = true;
|
|
69
71
|
var config = Resources.Load<ConfigAsset>("AmaGDKConfig");
|
|
72
|
+
|
|
70
73
|
#if UNITY_EDITOR
|
|
71
74
|
if (EditorApplication.isPlayingOrWillChangePlaymode)
|
|
72
75
|
{
|
|
@@ -56,11 +56,19 @@ namespace Amanotes.Core.Internal
|
|
|
56
56
|
return;
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
59
|
+
tempGO = UnityObject.Instantiate(prefab);
|
|
60
|
+
tempGO.name = "AmaGDK";
|
|
61
|
+
tempGO.transform.SetAsLastSibling();
|
|
62
62
|
Selection.activeObject = null;
|
|
63
|
-
|
|
63
|
+
EditorApplication.update -= DelaySelect;
|
|
64
|
+
EditorApplication.update += DelaySelect;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
private static GameObject tempGO;
|
|
68
|
+
private static void DelaySelect()
|
|
69
|
+
{
|
|
70
|
+
EditorApplication.update -= DelaySelect;
|
|
71
|
+
Selection.activeObject = tempGO;
|
|
64
72
|
}
|
|
65
73
|
#endif
|
|
66
74
|
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
using System;
|
|
2
2
|
using System.Collections;
|
|
3
3
|
using System.Collections.Generic;
|
|
4
|
-
using System.IO;
|
|
5
4
|
using System.Linq;
|
|
6
5
|
using System.Reflection;
|
|
7
6
|
using System.Text;
|
|
@@ -128,230 +127,7 @@ namespace Amanotes.Core.Internal
|
|
|
128
127
|
}
|
|
129
128
|
|
|
130
129
|
}
|
|
131
|
-
|
|
132
|
-
public static class GDKFileUtils
|
|
133
|
-
{
|
|
134
|
-
private static string _basePath;
|
|
135
|
-
public static string basePath
|
|
136
|
-
{
|
|
137
|
-
get
|
|
138
|
-
{
|
|
139
|
-
if (!string.IsNullOrEmpty(_basePath)) return _basePath;
|
|
140
|
-
_basePath = Application.isEditor
|
|
141
|
-
? Path.Combine(Directory.GetCurrentDirectory(), "Library", "AmaGDK")
|
|
142
|
-
: Path.Combine(Application.persistentDataPath, "AmaGDK");
|
|
143
|
-
|
|
144
|
-
if (!Directory.Exists(_basePath)) Directory.CreateDirectory(_basePath);
|
|
145
|
-
return _basePath;
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
internal static string GetPath(string fileName)
|
|
150
|
-
{
|
|
151
|
-
return Path.Combine(basePath, fileName);
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
internal static bool Exist(string fileName)
|
|
155
|
-
{
|
|
156
|
-
return File.Exists(GetPath(fileName));
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
public static void Save(string fileName, string content)
|
|
160
|
-
{
|
|
161
|
-
if (string.IsNullOrWhiteSpace(fileName))
|
|
162
|
-
{
|
|
163
|
-
LogWarningOnce("File name must be not null or empty");
|
|
164
|
-
return;
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
if (string.IsNullOrWhiteSpace(content))
|
|
168
|
-
{
|
|
169
|
-
LogWarningOnce($"Content for {fileName} is empty");
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
string path = GetPath(fileName);
|
|
173
|
-
|
|
174
|
-
try
|
|
175
|
-
{
|
|
176
|
-
File.WriteAllText(path, content);
|
|
177
|
-
}
|
|
178
|
-
catch (Exception ex)
|
|
179
|
-
{
|
|
180
|
-
LogWarningOnce(path + "\n" + ex);
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
internal static void SaveAppend(string fileName, IEnumerable<string> contents)
|
|
185
|
-
{
|
|
186
|
-
if (string.IsNullOrWhiteSpace(fileName))
|
|
187
|
-
{
|
|
188
|
-
LogWarningOnce("File name must be not null or empty");
|
|
189
|
-
return;
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
if (contents == null || !contents.GetEnumerator().MoveNext())
|
|
193
|
-
{
|
|
194
|
-
LogWarningOnce($"Content for {fileName} is empty");
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
string path = GetPath(fileName);
|
|
198
|
-
try
|
|
199
|
-
{
|
|
200
|
-
File.AppendAllLines(path, contents);
|
|
201
|
-
}
|
|
202
|
-
catch (Exception ex)
|
|
203
|
-
{
|
|
204
|
-
LogWarningOnce(path + "\n" + ex);
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
internal static void SaveAppend(string fileName, string content)
|
|
209
|
-
{
|
|
210
|
-
if (string.IsNullOrWhiteSpace(fileName))
|
|
211
|
-
{
|
|
212
|
-
LogWarningOnce("File name must be not null or empty");
|
|
213
|
-
return;
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
if (string.IsNullOrWhiteSpace(content))
|
|
217
|
-
{
|
|
218
|
-
LogWarningOnce($"Content for {fileName} is empty");
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
string path = GetPath(fileName);
|
|
222
|
-
try
|
|
223
|
-
{
|
|
224
|
-
File.AppendAllText(path, content);
|
|
225
|
-
}
|
|
226
|
-
catch (Exception ex)
|
|
227
|
-
{
|
|
228
|
-
LogWarningOnce(path + "\n" + ex);
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
public static string Load(string fileName)
|
|
233
|
-
{
|
|
234
|
-
var content = "";
|
|
235
|
-
|
|
236
|
-
if (string.IsNullOrWhiteSpace(fileName))
|
|
237
|
-
{
|
|
238
|
-
LogWarningOnce("File name must be not null or empty");
|
|
239
|
-
return content;
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
string path = GetPath(fileName);
|
|
243
|
-
if (!File.Exists(path)) return content;
|
|
244
|
-
|
|
245
|
-
try
|
|
246
|
-
{
|
|
247
|
-
content = File.ReadAllText(path);
|
|
248
|
-
}
|
|
249
|
-
catch (Exception ex)
|
|
250
|
-
{
|
|
251
|
-
LogWarningOnce(path + "\n" + ex);
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
return content;
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
public static async Task<string> LoadFromStreamingAssets(string fileName)
|
|
258
|
-
{
|
|
259
|
-
string filePath = Path.Combine(Application.streamingAssetsPath, fileName);
|
|
260
|
-
|
|
261
|
-
// Android
|
|
262
|
-
if (Application.platform == RuntimePlatform.Android)
|
|
263
|
-
{
|
|
264
|
-
using (UnityWebRequest request = UnityWebRequest.Get(filePath))
|
|
265
|
-
{
|
|
266
|
-
var operation = request.SendWebRequest();
|
|
267
|
-
while (!operation.isDone)
|
|
268
|
-
{
|
|
269
|
-
await Task.Yield();
|
|
270
|
-
}
|
|
271
|
-
if (request.result != UnityWebRequest.Result.Success)
|
|
272
|
-
{
|
|
273
|
-
LogWarning($"Error reading file: {request.error}");
|
|
274
|
-
return null;
|
|
275
|
-
}
|
|
276
|
-
return request.downloadHandler.text;
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
// Other
|
|
281
|
-
try
|
|
282
|
-
{
|
|
283
|
-
return File.ReadAllText(filePath);
|
|
284
|
-
}
|
|
285
|
-
catch (Exception e)
|
|
286
|
-
{
|
|
287
|
-
LogWarning($"Error reading file: {e.Message}");
|
|
288
|
-
}
|
|
289
|
-
return null;
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
internal static void Delete(string fileName)
|
|
293
|
-
{
|
|
294
|
-
string path = GetPath(fileName);
|
|
295
|
-
if (!File.Exists(path)) return;
|
|
296
|
-
|
|
297
|
-
try
|
|
298
|
-
{
|
|
299
|
-
File.Delete(path);
|
|
300
|
-
}
|
|
301
|
-
catch (Exception ex)
|
|
302
|
-
{
|
|
303
|
-
LogWarningOnce(path + "\n" + ex);
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
public static void ClearCacheData()
|
|
308
|
-
{
|
|
309
|
-
var sb = GDKPool.GetStringBuilder();
|
|
310
|
-
sb.AppendLine("[AmaGDK] All cached data & stats cleared");
|
|
311
|
-
|
|
312
|
-
if (!Directory.Exists(basePath))
|
|
313
|
-
{
|
|
314
|
-
sb.AppendLine("Cache path not exists: " + basePath);
|
|
315
|
-
return;
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
string[] filePaths = Directory.GetFiles(basePath);
|
|
319
|
-
foreach (string path in filePaths)
|
|
320
|
-
{
|
|
321
|
-
Delete(path);
|
|
322
|
-
sb.AppendLine($"[deleted] - {path}");
|
|
323
|
-
}
|
|
324
|
-
Debug.Log(sb);
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
public static T LoadJsonFromFile<T>(T instance) where T: new()
|
|
328
|
-
{
|
|
329
|
-
instance ??= new T();
|
|
330
|
-
|
|
331
|
-
string fileName = instance.GetType().Name;
|
|
332
|
-
string json = Load(fileName);
|
|
333
|
-
if (!string.IsNullOrEmpty(json))
|
|
334
|
-
{
|
|
335
|
-
try
|
|
336
|
-
{
|
|
337
|
-
JsonUtility.FromJsonOverwrite(json, instance);
|
|
338
|
-
} catch (Exception e)
|
|
339
|
-
{
|
|
340
|
-
LogWarning("LoadJsonFromFile error: " + fileName + "\n" + e);
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
return instance;
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
public static void SaveJsonToFile<T>(T instance)
|
|
348
|
-
{
|
|
349
|
-
string fileName = instance.GetType().Name;
|
|
350
|
-
string json = JsonUtility.ToJson(instance);
|
|
351
|
-
Save(fileName, json);
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
|
|
130
|
+
|
|
355
131
|
public class ActionQueue
|
|
356
132
|
{
|
|
357
133
|
private bool isProcessing;
|
|
@@ -419,14 +195,14 @@ namespace Amanotes.Core.Internal
|
|
|
419
195
|
|
|
420
196
|
internal static class JsonFileExtension
|
|
421
197
|
{
|
|
422
|
-
|
|
198
|
+
internal static T LoadJsonFromFile<T>(this T instance) where T : IJsonFile, new()
|
|
423
199
|
{
|
|
424
200
|
return GDKFileUtils.LoadJsonFromFile(instance);
|
|
425
201
|
}
|
|
426
202
|
|
|
427
|
-
|
|
203
|
+
internal static void SaveJsonToFile<T>(this T instance, bool immediately) where T: IJsonFile
|
|
428
204
|
{
|
|
429
|
-
GDKFileUtils.SaveJsonToFile(instance);
|
|
205
|
+
GDKFileUtils.SaveJsonToFile(instance, immediately);
|
|
430
206
|
}
|
|
431
207
|
}
|
|
432
208
|
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
using System;
|
|
2
|
+
using System.Collections.Generic;
|
|
3
|
+
using System.IO;
|
|
4
|
+
using System.Threading.Tasks;
|
|
5
|
+
using UnityEngine;
|
|
6
|
+
using UnityEngine.Networking;
|
|
7
|
+
using static Amanotes.Core.GDKDebug;
|
|
8
|
+
|
|
9
|
+
namespace Amanotes.Core.Internal
|
|
10
|
+
{
|
|
11
|
+
public static class GDKFileUtils
|
|
12
|
+
{
|
|
13
|
+
private static string _basePath;
|
|
14
|
+
public static string basePath
|
|
15
|
+
{
|
|
16
|
+
get
|
|
17
|
+
{
|
|
18
|
+
if (!string.IsNullOrEmpty(_basePath)) return _basePath;
|
|
19
|
+
_basePath = Application.isEditor
|
|
20
|
+
? Path.Combine(Directory.GetCurrentDirectory(), "Library", "AmaGDK")
|
|
21
|
+
: Path.Combine(Application.persistentDataPath, "AmaGDK");
|
|
22
|
+
|
|
23
|
+
if (!Directory.Exists(_basePath)) Directory.CreateDirectory(_basePath);
|
|
24
|
+
return _basePath;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
internal static string GetPath(string fileName)
|
|
29
|
+
{
|
|
30
|
+
return Path.Combine(basePath, fileName);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
internal static bool Exist(string fileName)
|
|
34
|
+
{
|
|
35
|
+
return File.Exists(GetPath(fileName));
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
public static void Save(string fileName, string content, bool immediately = true)
|
|
39
|
+
{
|
|
40
|
+
if (string.IsNullOrWhiteSpace(fileName))
|
|
41
|
+
{
|
|
42
|
+
LogWarningOnce("File name must be not null or empty");
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (string.IsNullOrWhiteSpace(content))
|
|
47
|
+
{
|
|
48
|
+
LogWarningOnce($"Content for {fileName} is empty");
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
ThreadWrite(fileName, content, immediately);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
private static void ThreadWrite(string fileName, string content, bool immediately)
|
|
55
|
+
{
|
|
56
|
+
// Only write on main thread if immediately is true
|
|
57
|
+
if (!immediately && GDKUtils.isOnMainThread)
|
|
58
|
+
{
|
|
59
|
+
Task.Run(()=>ThreadWrite(fileName, content, true))
|
|
60
|
+
.ConfigureAwait(false);
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
string filePath = GetPath(fileName);
|
|
65
|
+
try
|
|
66
|
+
{
|
|
67
|
+
File.WriteAllText(filePath, content);
|
|
68
|
+
}
|
|
69
|
+
catch (Exception ex)
|
|
70
|
+
{
|
|
71
|
+
LogWarningOnce($"Exception in ThreadWrite(): {filePath}\n{ex}");
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
internal static void SaveAppend(string fileName, IEnumerable<string> contents)
|
|
76
|
+
{
|
|
77
|
+
if (string.IsNullOrWhiteSpace(fileName))
|
|
78
|
+
{
|
|
79
|
+
LogWarningOnce("File name must be not null or empty");
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (contents == null || !contents.GetEnumerator().MoveNext())
|
|
84
|
+
{
|
|
85
|
+
LogWarningOnce($"Content for {fileName} is empty");
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
string path = GetPath(fileName);
|
|
89
|
+
try
|
|
90
|
+
{
|
|
91
|
+
File.AppendAllLines(path, contents);
|
|
92
|
+
}
|
|
93
|
+
catch (Exception ex)
|
|
94
|
+
{
|
|
95
|
+
LogWarningOnce(path + "\n" + ex);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
internal static void SaveAppend(string fileName, string content)
|
|
100
|
+
{
|
|
101
|
+
if (string.IsNullOrWhiteSpace(fileName))
|
|
102
|
+
{
|
|
103
|
+
LogWarningOnce("File name must be not null or empty");
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (string.IsNullOrWhiteSpace(content))
|
|
108
|
+
{
|
|
109
|
+
LogWarningOnce($"Content for {fileName} is empty");
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
string path = GetPath(fileName);
|
|
113
|
+
try
|
|
114
|
+
{
|
|
115
|
+
File.AppendAllText(path, content);
|
|
116
|
+
}
|
|
117
|
+
catch (Exception ex)
|
|
118
|
+
{
|
|
119
|
+
LogWarningOnce(path + "\n" + ex);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
public static string Load(string fileName)
|
|
124
|
+
{
|
|
125
|
+
var content = "";
|
|
126
|
+
|
|
127
|
+
if (string.IsNullOrWhiteSpace(fileName))
|
|
128
|
+
{
|
|
129
|
+
LogWarningOnce("File name must be not null or empty");
|
|
130
|
+
return content;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
string path = GetPath(fileName);
|
|
134
|
+
if (!File.Exists(path)) return content;
|
|
135
|
+
|
|
136
|
+
try
|
|
137
|
+
{
|
|
138
|
+
content = File.ReadAllText(path);
|
|
139
|
+
}
|
|
140
|
+
catch (Exception ex)
|
|
141
|
+
{
|
|
142
|
+
LogWarningOnce(path + "\n" + ex);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return content;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
public static async Task<string> LoadFromStreamingAssets(string fileName)
|
|
149
|
+
{
|
|
150
|
+
string filePath = Path.Combine(Application.streamingAssetsPath, fileName);
|
|
151
|
+
|
|
152
|
+
// Android
|
|
153
|
+
if (Application.platform == RuntimePlatform.Android)
|
|
154
|
+
{
|
|
155
|
+
using (UnityWebRequest request = UnityWebRequest.Get(filePath))
|
|
156
|
+
{
|
|
157
|
+
var operation = request.SendWebRequest();
|
|
158
|
+
while (!operation.isDone)
|
|
159
|
+
{
|
|
160
|
+
await Task.Yield();
|
|
161
|
+
}
|
|
162
|
+
if (request.result != UnityWebRequest.Result.Success)
|
|
163
|
+
{
|
|
164
|
+
LogWarning($"Error reading file: {request.error}");
|
|
165
|
+
return null;
|
|
166
|
+
}
|
|
167
|
+
return request.downloadHandler.text;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Other
|
|
172
|
+
try
|
|
173
|
+
{
|
|
174
|
+
return File.ReadAllText(filePath);
|
|
175
|
+
}
|
|
176
|
+
catch (Exception e)
|
|
177
|
+
{
|
|
178
|
+
LogWarning($"Error reading file: {e.Message}");
|
|
179
|
+
}
|
|
180
|
+
return null;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
internal static void Delete(string fileName)
|
|
185
|
+
{
|
|
186
|
+
string path = GetPath(fileName);
|
|
187
|
+
if (!File.Exists(path)) return;
|
|
188
|
+
|
|
189
|
+
try
|
|
190
|
+
{
|
|
191
|
+
File.Delete(path);
|
|
192
|
+
}
|
|
193
|
+
catch (Exception ex)
|
|
194
|
+
{
|
|
195
|
+
LogWarningOnce(path + "\n" + ex);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
public static void ClearCacheData()
|
|
200
|
+
{
|
|
201
|
+
var sb = GDKPool.GetStringBuilder();
|
|
202
|
+
sb.AppendLine("[AmaGDK] All cached data & stats cleared");
|
|
203
|
+
|
|
204
|
+
if (!Directory.Exists(basePath))
|
|
205
|
+
{
|
|
206
|
+
sb.AppendLine("Cache path not exists: " + basePath);
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
string[] filePaths = Directory.GetFiles(basePath);
|
|
211
|
+
foreach (string path in filePaths)
|
|
212
|
+
{
|
|
213
|
+
Delete(path);
|
|
214
|
+
sb.AppendLine($"[deleted] - {path}");
|
|
215
|
+
}
|
|
216
|
+
Debug.Log(sb);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
public static T LoadJsonFromFile<T>(T instance) where T: new()
|
|
220
|
+
{
|
|
221
|
+
instance ??= new T();
|
|
222
|
+
|
|
223
|
+
string fileName = instance.GetType().Name;
|
|
224
|
+
string json = Load(fileName);
|
|
225
|
+
if (!string.IsNullOrEmpty(json))
|
|
226
|
+
{
|
|
227
|
+
try
|
|
228
|
+
{
|
|
229
|
+
JsonUtility.FromJsonOverwrite(json, instance);
|
|
230
|
+
} catch (Exception e)
|
|
231
|
+
{
|
|
232
|
+
LogWarning("LoadJsonFromFile error: " + fileName + "\n" + e);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
return instance;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
public static void SaveJsonToFile<T>(T instance, bool immediately)
|
|
240
|
+
{
|
|
241
|
+
string fileName = instance.GetType().Name;
|
|
242
|
+
string json = JsonUtility.ToJson(instance);
|
|
243
|
+
ThreadWrite(fileName, json, immediately);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|