在window版时应该不会有太大问题这里就不叙述了
直接说在移动端时需要注意的
一、文件路径
文件路径网上已经很多介绍了,这里就简单的说下
参考地址:https://blog.csdn.net/wangshipeng409/article/details/93046648
1、Resources路径
Resources文件夹下的资源不管是否有用,全部会打包进.apk或者.ipa,并且打包时会将里面的资源压缩处理。加载方法是Resources.Load(文件名),需要注意:文件名不包括扩展名,打包后这个文件夹下的东西只能读不能写
2、application.dataPath路径 这个返回的是程序的数据文件所在文件夹的路径,但是在移动端它是完全没用。
3、application.streamingAssetsPath路径
这个用返回路径为相对路径,适合设置一些外部数据文件的路径。在Unity工程的Assets目录下起一个名为“StreamingAssets”的文件夹即可,然后用application.streamingAssetsPath访问,这个文件夹中的资源在打包时会原封不动的打包进去,不会压缩,在PC/MAC中可实现对文件的“增删改查”等操作,但在移动端是一个只读路径。不能写入
4、application.persistentDataPath路径
这个返回一个持久化数据存储目录的路径,可以在此路径下存储一些持久化的数据文件。这个路径可读、可写,但是只能在程序运行时才能读写操作,不能提前将数据放入这个路径。注意:如果在Android设置保存在沙盒中,那么就必须root以后才能用电脑取出文件,因此建议写入sdcard里。一般情况下,建议将获得的文件保存在这个路径下,例如可以从StreamingAsset中读取的二进制文件或者从AssetBundle读取的文件写入PersistentDatapath。
5、application.temporaryCachePath路径
此属性返回一个临时数据的缓存目录,跟application.persistentDataPath类似,但是在IOS上不能被自动备份。
6、/sdcard/…路径 表示Android手机的SD卡根目录。
7、/storage/emulated/0/…路径(这个路径我查找了好久……) 表示Android手机的内置存储根目录。
以上各路径中的资源加载方式都可以用WWW类加载,但要注意各个平台路径需要加的访问名称,例如Android平台的路径前要加"jar:file://“,其他平台使用"file://”。以下是各路径在各平台中的具体位置信息:
Android平台 application.dataPath : /data/app/xxx.xxx.xxx.apk
application.streamingAssetsPath :
jar:file:///data/app/xxx.xxx.xxx.apk/!/assets
application.persistentDataPath : /data/data/xxx.xxx.xxx/files
application.temporaryCachePath : /data/data/xxx.xxx.xxx/cache IOS平台
application.dataPath :
application/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/xxx.app/Data
application.streamingAssetsPath :
application/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/xxx.app/Data/Raw
application.persistentDataPath :
application/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/Documents
application.temporaryCachePath :
application/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/Library/Caches
Windows Web Player application.dataPath : file:///D:/MyGame/WebPlayer
(即导包后保存的文件夹,html文件所在文件夹) application.streamingAssetsPath :
application.persistentDataPath : application.temporaryCachePath :
二、不要写在移动端不能执行的代码
例如下面这段代码,下面这段是在resources文件夹里创建文件夹,但是一旦打包后resources文件夹就会被压缩,就没办法执行创建的事件。然后会导致这个脚本崩溃不在执行本脚本以及后面的代码。因此如果还在这脚本后面还写有读写的代码的话都不会执行。因此有时没有读写出数据其实并不是读写不了,而是因为脚本崩了导致没有执行读写代码。
void Awake()
{
判断是否有文件夹如果没有就创建文件夹
//DirectoryInfo myResources = new DirectoryInfo(Application.dataPath + "/Resources");
//DirectoryInfo myInfos = new DirectoryInfo(Application.dataPath + "/Resources/VariousInfos");
//if (myResources.Exists)
//{
// if (!myInfos.Exists)
// {
// Directory.CreateDirectory(Application.dataPath + "/Resources/" + "VariousInfos");
// }
//}
//else
//{
// Directory.CreateDirectory(Application.dataPath + "/" + "Resources");
// Directory.CreateDirectory(Application.dataPath + "/Resources/" + "VariousInfos");
//}
}
三、读写权限问题
移动端都会有个读写权限问题,如果读写不了可以能是没有读写权限
例如安卓平台,对应的要在Assets/Plugins/Android文件夹下放入权限的xml文件:AndroidManifest.xml
AndroidManifest.xml文件会在打包一次后在对应的项目目录下有个Temp/StagingArea文件下自动生成一个放到Plugins/Android文件夹中就行了,但是因为是自动生成的因此里面只会有一些默认的参数,如果没有自动生成的参数需要自行添加
参数参考链接:https://blog.csdn.net/linli1991/article/details/81531134
暂时就这么多,各位大佬如果还有补充的欢迎评论留言
下面附上我写的通过.net读和streamwriter写入的代码
(以下的读写xml代码是能在安卓端正常运行读写的)
写的不怎么好,请不要喷,里面有一些数据结构是自定义的,我没有整个脚本复制过来,如果复制我写的函数代码改写时请自行改对应的数据结构
//将数据文件复制到Persistent路径下
public static void SetFileToPersistent()
{
FileInfo info = new FileInfo(Application.persistentDataPath + "/PlayerInfo.xml");
if (!info.Exists)
{
try
{
TextAsset ts = Resources.Load("VariousInfos/PlayerInfo") as TextAsset;
string content = ts.text;
using (FileStream fs = new FileStream(Application.persistentDataPath + "/PlayerInfo.xml", FileMode.OpenOrCreate))
{
using (StreamWriter sw = new StreamWriter(fs, Encoding.UTF8))
{
sw.Write(content);
sw.Close();
}
fs.Close();
}
}
catch (Exception ex)
{
Debug.Log(ex);
}
}
}
//创建xml文件和根节点(文件名,路径,根节点名)
public bool CreateXml(string FileName = null, string FilePath = null, string RootName = null, bool IsUseXmlSave = false)
{
if (FileName == null) FileName = "PlayerInfo.xml";
if (FilePath == null) FilePath = Application.persistentDataPath + "/";
if (RootName == null) RootName = "PlayerInfoDatas";
if (!File.Exists(FilePath + FileName))
{
XmlDocument xml = new XmlDocument();
XmlElement root = xml.CreateElement(RootName);
xml.AppendChild(root);
//保存xml文件
if (IsUseXmlSave)
{
xml.Save(FilePath+FileName);
}
else
{
using (FileStream fs = new FileStream(FilePath + FileName, FileMode.OpenOrCreate))
{
using (StreamWriter sw = new StreamWriter(fs, Encoding.UTF8))
{
sw.Write(xml.OuterXml);
sw.Close();
}
fs.Close();
}
}
return true;
}
return false;
}
//添加节点(玩家金币,关卡Id,是否解锁,拥有的图片碎片数量,一共的图片碎片数量,文件名,文件路径,根节点名)
public bool AddPlayerDataToXml(int PlayerGold = 0, bool IsRefreshItem = false, int TipsItems = 0, int MaxTipsItems = 3, int RefreshItemTime = 1800, string SaveTime = null, bool IsFirstGetChip = true, int LevelId = 1, bool IsUnlock = false, int OwnedImageChipNumber = 0, int MaxImageChipNumber = 1,bool IsShowChipTipps=false, int PlayGameNumber=0,string FileName = null, string FilePath = null, string RootName = null,bool IsUseXmlSave= false)
{
if (FileName == null) FileName = "PlayerInfo.xml";
if (FilePath == null) FilePath = Application.persistentDataPath + "/";
if (RootName == null) RootName = "PlayerInfoDatas";
if (SaveTime == null) SaveTime = System.DateTime.Now.ToString();
if (IsRefreshItem == true && TipsItems <= 0) { TipsItems = MaxTipsItems; IsRefreshItem = false; }
//有文件时
if (File.Exists(FilePath + FileName))
{
try
{
//读文件
if (xml.OuterXml == null || xml.OuterXml == string.Empty)
{
XmlReaderSettings st = new XmlReaderSettings();
st.IgnoreComments = true;
XmlReader reader = XmlReader.Create(FilePath + FileName, st);
xml.Load(reader);
reader.Close();
}
//获取根节点
XmlNode root = xml.SelectSingleNode(RootName);
//获取根节点下的第一个节点
XmlNode rootChild = root.FirstChild;
XmlNodeList elementList = null;
XmlElement element = (XmlElement)root.FirstChild;
//判断根节点下的第一个节点是否存在
if (element != null)
{
element.SetAttribute("PlayerGold", PlayerGold.ToString());
element.SetAttribute("IsRefreshItem", IsRefreshItem.ToString());
element.SetAttribute("TipsItems", TipsItems.ToString());
element.SetAttribute("MaxTipsItems", MaxTipsItems.ToString());
element.SetAttribute("RefreshItemTime", RefreshItemTime.ToString());
element.SetAttribute("SaveTime", SaveTime);
element.SetAttribute("IsFirstGetChip", IsFirstGetChip.ToString());
element.SetAttribute("IsShowChipTipps", IsShowChipTipps.ToString());
element.SetAttribute("PlayGameNumber", PlayGameNumber.ToString());
elementList = rootChild.ChildNodes;
}
else
{
element = xml.CreateElement("PlayerDatas");
element.SetAttribute("PlayerGold", PlayerGold.ToString());
element.SetAttribute("IsRefreshItem", IsRefreshItem.ToString());
element.SetAttribute("TipsItems", TipsItems.ToString());
element.SetAttribute("MaxTipsItems", MaxTipsItems.ToString());
element.SetAttribute("RefreshItemTime", RefreshItemTime.ToString());
element.SetAttribute("SaveTime", SaveTime);
element.SetAttribute("IsFirstGetChip", IsFirstGetChip.ToString());
element.SetAttribute("IsShowChipTipps", IsShowChipTipps.ToString());
element.SetAttribute("PlayGameNumber", PlayGameNumber.ToString());
elementList = element.ChildNodes;
}
//获取根节点下的第一个节点下的所有节点
foreach (XmlElement child in elementList)
{
int id = 0; int.TryParse(child.GetAttribute("LevelId"), out id);
if (id == LevelId)
{
child.SetAttribute("LevelId", LevelId.ToString());
child.SetAttribute("IsUnlock", IsUnlock.ToString());
child.SetAttribute("OwnedImageChipNumber", OwnedImageChipNumber.ToString());
child.SetAttribute("MaxImageChipNumber", MaxImageChipNumber.ToString());
//保存到XML
if (IsUseXmlSave)
{
element.AppendChild(child);
root.AppendChild(element);
xml.AppendChild(root);
xml.Save(FilePath + FileName);
}
else
{
DeleteXmlFile();
using (FileStream fs = new FileStream(FilePath + FileName, FileMode.OpenOrCreate))
{
using (StreamWriter sw = new StreamWriter(fs, Encoding.UTF8))
{
sw.Write(xml.OuterXml);
sw.Close();
}
fs.Close();
}
}
return true;
}
}
//当根节点下的第一个节点下没有对应的节点时创建节点保存数据
XmlElement elementchild = xml.CreateElement("LevelId");
elementchild.SetAttribute("LevelId", LevelId.ToString());
elementchild.SetAttribute("IsUnlock", IsUnlock.ToString());
elementchild.SetAttribute("OwnedImageChipNumber", OwnedImageChipNumber.ToString());
elementchild.SetAttribute("MaxImageChipNumber", MaxImageChipNumber.ToString());
//保存到XML
if (IsUseXmlSave)
{
element.AppendChild(elementchild);
root.AppendChild(element);
xml.AppendChild(root);
xml.Save(FilePath + FileName);
}
else
{
DeleteXmlFile();
using (FileStream fs = new FileStream(FilePath + FileName, FileMode.OpenOrCreate))
{
using (StreamWriter sw = new StreamWriter(fs, Encoding.UTF8))
{
sw.Write(xml.OuterXml);
sw.Close();
}
fs.Close();
}
}
return true;
}
catch (Exception ex)
{
Debug.Log(ex);
if (output != null)
output.text = ex.ToString();
}
}
return false;
}
//读取Xml文件数据
public bool ReadXml(ref PlayerInfo Datas, Text test=null, string FileName = null, string FilePath = null, string RootName = null)
{
try
{
if (FileName == null) FileName = "PlayerInfo.xml";
if (FilePath == null) FilePath = Application.persistentDataPath + "/";
if (RootName == null) RootName = "PlayerInfoDatas";
//读文件
if (xml.OuterXml == null || xml.OuterXml == string.Empty)
{
XmlReaderSettings st = new XmlReaderSettings();
st.IgnoreComments = true;
XmlReader reader = XmlReader.Create(FilePath + FileName, st);
xml.Load(reader);
reader.Close();
}
if (test != null)
test.text = "runing this fun";
XmlNode root = xml.SelectSingleNode(RootName);
int.TryParse(root.FirstChild.Attributes.GetNamedItem("PlayerGold").Value, out Datas.PlayerGold);
bool.TryParse(root.FirstChild.Attributes.GetNamedItem("IsRefreshItem").Value, out Datas.IsRefreshItem);
int.TryParse(root.FirstChild.Attributes.GetNamedItem("TipsItems").Value, out Datas.TipsItems);
int.TryParse(root.FirstChild.Attributes.GetNamedItem("MaxTipsItems").Value, out Datas.MaxTipsItems);
int.TryParse(root.FirstChild.Attributes.GetNamedItem("RefreshItemTime").Value, out Datas.RefreshItemTime);
System.DateTime.TryParse(root.FirstChild.Attributes.GetNamedItem("SaveTime").Value, out Datas.SaveTime);
bool.TryParse(root.FirstChild.Attributes.GetNamedItem("IsFirstGetChip").Value, out Datas.IsFirstGetChip);
bool.TryParse(root.FirstChild.Attributes.GetNamedItem("IsShowChipTipps").Value, out Datas.IsShowChipTipps);
int.TryParse(root.FirstChild.Attributes.GetNamedItem("PlayGameNumber").Value, out Datas.PlayGameNumber);
XmlNodeList elementList = root.FirstChild.ChildNodes;
foreach (XmlElement child in elementList)
{
LevelDataBase tempImageData = new LevelDataBase();
int.TryParse(child.GetAttribute("LevelId"), out tempImageData.LevelId);
bool.TryParse(child.GetAttribute("IsUnlock"), out tempImageData.IsUnlock);
int.TryParse(child.GetAttribute("OwnedImageChipNumber"), out tempImageData.OwnedImageChipNumber);
int.TryParse(child.GetAttribute("MaxImageChipNumber"), out tempImageData.MaxImageChipNumber);
Datas.LevelDatas[tempImageData.LevelId] = tempImageData;
}
}
catch (Exception ex)
{
Debug.Log(ex);
if (output != null)
output.text = ex.ToString();
}
return true;
}
//删除Xml文件
public bool DeleteXmlFile(string FileName = null, string FilePath = null)
{
if (FileName == null) FileName = "PlayerInfo.xml";
if (FilePath == null) FilePath = Application.persistentDataPath + "/";
if (File.Exists(FilePath + FileName))
{
File.Delete(FilePath + FileName);
return true;
}
else
{
return false;
}
}