文件系统安卓适配

This commit is contained in:
2025-12-17 20:52:56 +08:00
parent 529ba19c99
commit e58184bd00
12 changed files with 167 additions and 174 deletions
@@ -13,7 +13,6 @@ namespace AibisDream.Kit
{
public class ConfigUtil : SingletonBase<ConfigUtil>
{
private const string CharacterConfigPath = "/Config/character.csv";
private const string SpriteGroupPath = "/Config/sprite_group.json";
private Dictionary<string, Character> _characters;
@@ -42,12 +41,12 @@ namespace AibisDream.Kit
public override void OnSingletonInit()
{
InitCharacterConfig();
InitSpriteGroupConfig();
// InitSpriteGroupConfig();
}
private void InitCharacterConfig()
{
var characterList = CsvUtil.ReadAsBean<Character>(Application.streamingAssetsPath + CharacterConfigPath);
var characterList = CsvUtil.ReadAsBean<Character>(ConstRef.CharacterConfigPath);
_characters = characterList.ToDictionary(item => item.Key, item => item);
}
+3 -2
View File
@@ -1,4 +1,5 @@
using System;
using System.IO;
using UnityEngine;
namespace AibisDream.Kit
@@ -14,7 +15,7 @@ namespace AibisDream.Kit
/// <summary>
/// 日志文件路径
/// </summary>
public static string LogPath => Application.streamingAssetsPath + "/LogFile";
public static string LogPath => Path.Combine(Application.streamingAssetsPath, "LogFile");
/// <summary>
/// 日志保存最近几天的内容
@@ -32,7 +33,7 @@ namespace AibisDream.Kit
private void Awake()
{
#if !UNITY_EDITOR
#if !UNITY_EDITOR && !UNITY_ANDROID && !UNITY_IOS
DontDestroyOnLoad(gameObject);
_fileLogger = new FileLogger(LogFileName, LogPath, SaveDays);
LogMessage($"Ver.{Application.version}", "", LogType.Log);
@@ -112,7 +112,9 @@ namespace AibisDream
public void SaveUnloadChapters()
{
#if !UNITY_ANDROID || UNITY_EDITOR
JsonUtil.SaveArray(unlockedChapterList.ToArray(), ConstRef.ChapterProgressPath);
#endif
}
public bool TryGetSaveFilePath(out string saveFilePath)
+2 -1
View File
@@ -4,6 +4,7 @@ using AibisDream.Framework;
using AibisDream.Kit;
using AibisDream.UI;
using UnityEngine;
using System.IO;
namespace AibisDream
{
@@ -12,7 +13,7 @@ namespace AibisDream
/// </summary>
public class SettingLoader
{
private static readonly string SettingPath = Application.streamingAssetsPath + "/Config/setting.json";
private static readonly string SettingPath = Path.Combine(Application.streamingAssetsPath, "Config", "setting.json");
private readonly ConfigContainer _container;
@@ -23,6 +23,9 @@ namespace AibisDream
private void InitCursor()
{
#if UNITY_ANDROID || UNITY_IOS
_cursor.gameObject.SetActive(false);
#endif
Cursor.visible = false;
_cursor.sprite = defaultCursor;
}
-77
View File
@@ -1,77 +0,0 @@
using System.IO;
using System.Linq;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
namespace AibisDream.UI
{
public class SavesPanel : MonoBehaviour, IUIPanel
{
public bool IsOpen => gameObject.activeSelf;
public bool IsCloseable => true;
private static readonly string SaveFilePath = Application.streamingAssetsPath + "/SaveFiles";
#region
public Button buttonPrefab;
public Transform buttonParent;
#endregion
#region
public void Show()
{
InitLevelBtn();
gameObject.SetActive(true);
RegisterButton();
}
public void Hide()
{
gameObject.SetActive(false);
UnRegisterButton();
}
private void RegisterButton()
{
var returnBtn = transform.Find("Return").GetComponent<Button>();
returnBtn.onClick.AddListener(() => UIManager.Instance.HidePanel<SavesPanel>());
}
private void UnRegisterButton()
{
var returnBtn = transform.Find("Return").GetComponent<Button>();
returnBtn.onClick.RemoveAllListeners();
}
#endregion
private void InitLevelBtn()
{
// 清空旧按钮
foreach (Transform child in buttonParent)
{
Destroy(child.gameObject);
}
// 加载存档文件
string[] saveFiles = Directory.GetFiles(SaveFilePath, "*.json");
var orderedSaveFiles = saveFiles.OrderByDescending(item => item).ToArray();
foreach (var saveFile in orderedSaveFiles)
{
var button = Instantiate(buttonPrefab, buttonParent);
button.GetComponentInChildren<TMP_Text>().text = Path.GetFileNameWithoutExtension(saveFile);
button.onClick.AddListener(() => OnSaveFileSelected(saveFile));
}
}
private void OnSaveFileSelected(string saveFileName)
{
// 隐藏UI
gameObject.SetActive(false);
// 开始游戏
GameManager.Instance.StartWithSaveFile(saveFileName);
}
}
}
@@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: bdd86c19be1449ca9e2783eb714fb8ff
timeCreated: 1745572533
-59
View File
@@ -1,59 +0,0 @@
using System.IO;
using System.Linq;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
namespace AibisDream
{
public class SaveFileUIController : MonoBehaviour
{
private static readonly string SaveFilePath = Application.streamingAssetsPath + "/SaveFiles";
#region
public Button buttonPrefab;
public Transform buttonParent;
public Button returnButton;
#endregion
private void Start()
{
returnButton.onClick.AddListener(HideSaveFileUI);
}
public void ShowSaveFileUI()
{
// 清空旧按钮
foreach (Transform child in buttonParent)
{
Destroy(child.gameObject);
}
// 加载存档文件
string[] saveFiles = Directory.GetFiles(SaveFilePath, "*.json");
var orderedSaveFiles = saveFiles.OrderByDescending(item => item).ToArray();
foreach (var saveFile in orderedSaveFiles)
{
var button = Instantiate(buttonPrefab, buttonParent);
button.GetComponentInChildren<TMP_Text>().text = Path.GetFileNameWithoutExtension(saveFile);
button.onClick.AddListener(() => OnSaveFileSelected(saveFile));
}
gameObject.SetActive(true);
}
private void OnSaveFileSelected(string saveFileName)
{
// 隐藏UI
gameObject.SetActive(false);
// 开始游戏
// GameLoopManager.Instance.StartWithSaveFile(saveFileName);
}
private void HideSaveFileUI()
{
gameObject.SetActive(false);
}
}
}
@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: a351e509c8dd5944f9e6406f59ea5c0b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+6 -3
View File
@@ -1,4 +1,5 @@
using UnityEngine;
using System.IO;
using UnityEngine;
namespace AibisDream.Utility
{
@@ -23,10 +24,12 @@ namespace AibisDream.Utility
#if UnityEditor
public static readonly string SaveFilePath = Application.persistentDataPath + "/SaveFiles/";
#else
public static readonly string SaveFilePath = Application.persistentDataPath + "/AllOurBrokenParts/saves/";
public static readonly string SaveFilePath = Path.Combine(Application.persistentDataPath, "AllOurBrokenParts", "saves");
#endif
public static readonly string ChapterProgressPath = $"{Application.streamingAssetsPath}/Config/chapter.json";
public static readonly string ChapterProgressPath = Path.Combine(Application.persistentDataPath, "AllOurBrokenParts", "Config", "chapter.json");
public static readonly string CharacterConfigPath = Path.Combine(Application.streamingAssetsPath, "Config", "character.csv");
#region
+89 -9
View File
@@ -9,6 +9,8 @@ using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using UnityEngine;
using UnityEngine.Networking;
namespace AibisDream.Utility
{
@@ -20,13 +22,89 @@ namespace AibisDream.Utility
// 默认分隔符
private const char FieldSeparator = ',';
/// <summary>
/// 根据平台读取文件内容
/// </summary>
private static string ReadFileText(string filePath)
{
#if UNITY_ANDROID && !UNITY_EDITOR
// Android 平台需要使用 UnityWebRequest 读取 StreamingAssets
if (filePath.Contains(Application.streamingAssetsPath))
{
// Android 上 StreamingAssets 在 APK 中,需要构建正确的 URL
string url = filePath;
// 确保使用正确的路径分隔符
url = url.Replace("\\", "/");
// 如果路径不包含协议前缀,添加 file://
if (!url.StartsWith("file://") && !url.StartsWith("jar:file://"))
{
// 对于 Android APK 中的文件,使用 jar:file:// 协议
string relativePath = url.Replace(Application.streamingAssetsPath, "").TrimStart('/');
url = "jar:file://" + Application.dataPath + "!/assets/" + relativePath;
}
using (UnityWebRequest www = UnityWebRequest.Get(url))
{
www.SendWebRequest();
// 等待请求完成(同步等待)
while (!www.isDone)
{
// 在主线程中等待
}
if (www.result == UnityWebRequest.Result.Success)
{
return www.downloadHandler.text;
}
else
{
throw new IOException($"无法读取文件: {filePath}, URL: {url}, 错误: {www.error}");
}
}
}
else
{
// 非 StreamingAssets 路径,使用普通文件读取
return File.ReadAllText(filePath, DefaultEncode);
}
#else
// 其他平台直接使用 File 类
return File.ReadAllText(filePath, DefaultEncode);
#endif
}
/// <summary>
/// 根据平台创建 StreamReader
/// </summary>
private static StreamReader CreateStreamReader(string filePath)
{
#if UNITY_ANDROID && !UNITY_EDITOR
// Android 平台需要使用 UnityWebRequest 读取 StreamingAssets
if (filePath.Contains(Application.streamingAssetsPath))
{
string fileText = ReadFileText(filePath);
MemoryStream stream = new MemoryStream(DefaultEncode.GetBytes(fileText));
return new StreamReader(stream, DefaultEncode);
}
else
{
// 非 StreamingAssets 路径,使用普通文件读取
return new StreamReader(filePath, DefaultEncode);
}
#else
// 其他平台直接使用 File 类
return new StreamReader(filePath, DefaultEncode);
#endif
}
public static List<string[]> Read(string filePath)
{
List<string[]> dataList = new List<string[]>();
StreamReader reader;
StreamReader reader = null;
try
{
using (reader = new StreamReader(filePath, DefaultEncode))
using (reader = CreateStreamReader(filePath))
{
while (!reader.EndOfStream)
{
@@ -48,7 +126,7 @@ namespace AibisDream.Utility
GC.Collect();
Thread.Sleep(50);
Console.WriteLine(ex.StackTrace);
using (reader = new StreamReader(filePath, DefaultEncode))
using (reader = CreateStreamReader(filePath))
{
while (!reader.EndOfStream)
{
@@ -59,8 +137,10 @@ namespace AibisDream.Utility
}
}
}
reader.Close();
finally
{
reader?.Close();
}
return dataList;
}
@@ -82,7 +162,7 @@ namespace AibisDream.Utility
var props = targetType.GetProperties();
// 读取CSV
using var reader = new StreamReader(filePath, DefaultEncode);
using var reader = CreateStreamReader(filePath);
// 第一行是注释
reader.ReadLine();
@@ -90,7 +170,7 @@ namespace AibisDream.Utility
var titles = reader.ReadLine()?.Split(FieldSeparator);
if (titles == null)
{
Debug.WriteLine("csv无标题");
System.Diagnostics.Debug.WriteLine("csv无标题");
throw new Exception("csv无标题");
}
@@ -130,7 +210,7 @@ namespace AibisDream.Utility
{
bool blnFlag = true;
StreamReader reader = new StreamReader(strPath, DefaultEncode);
StreamReader reader = CreateStreamReader(strPath);
myCsvDt = new DataTable();
while (reader.ReadLine() is { } strLine)
{
@@ -218,7 +298,7 @@ namespace AibisDream.Utility
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
System.Diagnostics.Debug.WriteLine(ex.Message);
sw.Close();
}
}
+60 -6
View File
@@ -4,6 +4,8 @@ using System.IO;
using System.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using UnityEngine;
using UnityEngine.Networking;
namespace AibisDream.Utility
{
@@ -11,6 +13,58 @@ namespace AibisDream.Utility
{
public const string JsonSuffix = ".json";
/// <summary>
/// 根据平台读取文件内容
/// </summary>
private static string ReadFileText(string filePath)
{
#if UNITY_ANDROID && !UNITY_EDITOR
// Android 平台需要使用 UnityWebRequest 读取 StreamingAssets
if (filePath.Contains(Application.streamingAssetsPath))
{
// Android 上 StreamingAssets 在 APK 中,需要构建正确的 URL
string url = filePath;
// 确保使用正确的路径分隔符
url = url.Replace("\\", "/");
// 如果路径不包含协议前缀,添加 file://
if (!url.StartsWith("file://") && !url.StartsWith("jar:file://"))
{
// 对于 Android APK 中的文件,使用 jar:file:// 协议
string relativePath = url.Replace(Application.streamingAssetsPath, "").TrimStart('/');
url = "jar:file://" + Application.dataPath + "!/assets/" + relativePath;
}
using (UnityWebRequest www = UnityWebRequest.Get(url))
{
www.SendWebRequest();
// 等待请求完成(同步等待)
while (!www.isDone)
{
// 在主线程中等待
}
if (www.result == UnityWebRequest.Result.Success)
{
return www.downloadHandler.text;
}
else
{
throw new IOException($"无法读取文件: {filePath}, URL: {url}, 错误: {www.error}");
}
}
}
else
{
// 非 StreamingAssets 路径,使用普通文件读取
return File.ReadAllText(filePath);
}
#else
// 其他平台直接使用 File 类
return File.ReadAllText(filePath);
#endif
}
/// <summary>
/// 按路径和Key加载
/// </summary>
@@ -21,7 +75,7 @@ namespace AibisDream.Utility
/// <exception cref="Exception">错误</exception>
public static T ReadBean<T>(string path, string key)
{
string json = File.ReadAllText(path);
string json = ReadFileText(path);
JObject jObject = JObject.Parse(json);
if (jObject.ContainsKey(key))
@@ -40,7 +94,7 @@ namespace AibisDream.Utility
/// <returns></returns>
public static T ReadBean<T>(string path)
{
string json = File.ReadAllText(path);
string json = ReadFileText(path);
return JsonConvert.DeserializeObject<T>(json);
}
@@ -61,7 +115,7 @@ namespace AibisDream.Utility
/// <returns>目标Bean</returns>
public static T[] ReadBeanArray<T>(string path)
{
string json = File.ReadAllText(path);
string json = ReadFileText(path);
return JsonConvert.DeserializeObject<T[]>(json);
}
@@ -73,7 +127,7 @@ namespace AibisDream.Utility
/// <returns>目标Bean</returns>
public static Dictionary<string, T> ReadBeanDict<T>(string path)
{
string json = File.ReadAllText(path);
string json = ReadFileText(path);
return JsonConvert.DeserializeObject<Dictionary<string, T>>(json);
}
@@ -84,7 +138,7 @@ namespace AibisDream.Utility
/// <returns>key列表</returns>
public static string[] ReadKeys(string path)
{
string json = File.ReadAllText(path);
string json = ReadFileText(path);
JObject jObject = JObject.Parse(json);
return jObject.Properties().Select(jProp => jProp.Name).ToArray();
@@ -92,7 +146,7 @@ namespace AibisDream.Utility
public static JObject ReadJObject(string path)
{
string json = File.ReadAllText(FormatAsJsonPath(path), System.Text.Encoding.UTF8);
string json = ReadFileText(FormatAsJsonPath(path));
return JObject.Parse(json);
}