PBXProjectEditor.cs
PBXProjectEditor.cs
#if UNITY_IOS
/**
* @file PBXProjectEditor.cs
* @brief PBXプロジェクトの編集を行う。
* @date $Date$
* @version $Rev$
* @author $Author$
*/
using UnityEditor;
using UnityEditor.iOS.Xcode;
using UnityEditor.iOS.Xcode.Extensions;
using System;
using System.IO;
using System.Collections.Generic;
namespace yyama2.Editor.XCProjEdit
{
/// <summary>
/// PBXプロジェクトのプロパティを設定する。
///
///
/// 設定は下記の様に定義してください。
///
/// ■file操作(追加・削除・移動) ※PBXParamFile.FileParam参照
/// new List() {
/// new PBXParamFile.FileParam(
/// type,
/// fromDir,
/// fromFile,
/// toDir,
/// toFile,
/// compileFlag // 省略可
/// ),
/// }
///
/// ■Framework ※PBXParamFramework参照
/// new Dictionary<string, int>() {
/// { "value.framework", 1 },
/// }
///
/// ■Property設定 ※PBXParamProperty.PropertyParams参照
/// new Dictionary<string, List<PBXParamProperty.PropertyParams>>() {
/// "property",
/// new List<PBXParamProperty.PropertyParams>() {
/// new PBXParamProperty.PropertyParams(
/// configType:"config_type", // configType
/// addValue:new string[]{ "YES" }, // AddValue
/// nremoveType:ew string[]{ "NO" }, // RemoveValue
/// forceOverride:false // 上書きフラグ
/// ),
/// }
/// },
/// </summary>
public static class PBXProjectEditor
{
/// <summary> Unityデフォルトのプロジェクト名(基本変更しなくていい)</summary>
public const string NATIVE_TARGET_NAME = "Unity-iPhone";
/// <summary> XcodeProjectの拡張子</summary>
public const string XCODE_PROJ_FILE_EXTENSION = ".xcodeproj";
/// <summary> XcodeProjectファイル</summary>
public const string XCODE_PROJ_FILE = NATIVE_TARGET_NAME + XCODE_PROJ_FILE_EXTENSION;
/// <summary> PBXプロジェクトファイル</summary>
public const string PBX_PROJ_FILE = "project.pbxproj";
/// <summary> project.pbxprojのパスを取得する</summary>
/// <param name="path"> project.pbxprojのあるフォルダパス</param>
/// <returns> project.pbxprojのファイルパス</returns>
public static string GetDefaultPBXProjectPath(string path)
{
return Path.Combine(Path.Combine(path, XCODE_PROJ_FILE), PBX_PROJ_FILE);
}
/// <summary>
/// PBXプロジェクトの編集
/// </summary>
/// <param name="pbxProjPath">Pbx proj path.</param>
/// <param name="pbxParams">Pbx parameters.</param>
/// <param name="callClass">この関数を呼び出しているクラスタイプ.ログ出力に飲み使用します.typeof( クラス )</param>
public static void PBXProjectEdit(string pbxProjPath, List<PBXParam> pbxParams, Type callClass = null, bool isMain = true)
{
string className = "";
if (callClass != null)
{
className += callClass.Name;
}
UnityEngine.Debug.Log("PBXProjectEditor:" + className);
string log = "======================= PBXProjectValue =======================\n";
UnityEngine.Debug.Log("pbxProjPath=>" + pbxProjPath);
PBXProject pbxProj = new PBXProject();
pbxProj.ReadFromFile(pbxProjPath);
foreach (PBXParam param in pbxParams)
{
param.Edit(ref pbxProj);
}
pbxProj.WriteToFile(pbxProjPath);
log += className + "\n";
foreach (PBXParam param in pbxParams)
{
log += param.GetParamLog();
}
log += "\n======================= PBXProjectValue =======================";
UnityEngine.Debug.Log(log);
}
}
/// <summary>
/// 設定項目のクラス。
/// </summary>
public abstract class PBXParam
{
public enum ProjectType
{
Main = 1 << 0,
Framework = 1 << 1,
}
/// <summary>
/// 設定されているパラメータのログ。
/// </summary>
/// <returns>The parameter log.</returns>
public abstract string GetParamLog();
/// <summary>
/// 設定の編集を行う
/// </summary>
/// <param name="pbxProj">Pbx projct.</param>
public abstract void Edit(ref PBXProject pbxProj);
/// <summary>
/// プロジェクト名のリスト(基本的には、Unity-iPhoneのみ)
/// </summary>
private ProjectType m_projectType;
/// <summary>
/// プロジェクトのguidを取得する。
/// </summary>
/// <returns>The project guids.</returns>
/// <param name="pbxProj">Pbx project.</param>
protected IEnumerable<string> GetProjectGuids(PBXProject pbxProj)
{
var guids = new List<string>();
if ((m_projectType & ProjectType.Main) == ProjectType.Main)
{
guids.Add(pbxProj.GetUnityMainTargetGuid());
}
if ((m_projectType & ProjectType.Framework) == ProjectType.Framework)
{
guids.Add(pbxProj.GetUnityFrameworkTargetGuid());
}
return guids;
}
/// <summary>
/// コンストラクタ。継承先のクラスで必ず呼び出すこと( GetProjectGuids()で使用します。 )
/// </summary>
/// <param name="projectType">Project types.</param>
public PBXParam(ProjectType projectType)
{
m_projectType = projectType;
}
}
/// <summary>
/// プロジェクトに設定されているファイルを追加するクラス。
/// </summary>
public class PBXParamFile : PBXParam
{
/// <summary> 編集を行うかどうか</summary>
private readonly List<FileParam> m_params;
/// <summary> Xcodeプロジェクトのディレクトリ</summary>
private readonly string m_xcodePath;
/// <summary>
/// どのようなファイル操作を行うか。
/// </summary>
public enum FileEditType
{
/// <summary> ファイルの追加 </summary>
ADD,
/// <summary> ファイルのリネーム(移動)</summary>
MOVE,
/// <summary> ファイルの削除(物理削除は行わない)</summary>
REMOVE,
}
/// <summary>
/// 変更設定。
/// </summary>
public class FileParam
{
/// <summary> edit type.</summary>
public FileEditType Type { get; private set; }
/// <summary> form directory path.</summary>
public string FromDirPath { get; private set; }
/// <summary> from file name.</summary>
public string FromFileName { get; private set; }
/// <summary> to directory path.</summary>
public string ToDirPath { get; private set; }
/// <summary> to file name.</summary>
public string ToFileName { get; private set; }
/// <summary> to file name.</summary>
public string CompileFlags { get; private set; }
public bool CodeSignOnCopy { get; private set; }
public bool RemoveHeadersOnCopy { get; private set; }
/// <summary>
/// <para>指定するタイプによって引数の使い分けを行う。</para>
/// <para></para>
/// <para>ADD</para>
/// <para>(Unityから自動で転送されないファイルをXcodeに転送してプロジェクトに追加する)</para>
/// <para>_fromDir : Unity上(Assetsを除く)</para>
/// <para>fromFile : Unity上のファイル名</para>
/// <para>___toDir : Xcode上のディレクトリ</para>
/// <para>__toFile : Xcode上のファイル名</para>
/// <para></para>
/// <para>MOVE</para>
/// <para>(Xcode上からファイルを移動(リネーム)する)</para>
/// <para>_fromDir : Xcode上で移動前のディレクトリ</para>
/// <para>fromFile : Xcode上で移動前のファイル名</para>
/// <para>___toDir : Xcode上で移動後のディレクトリ</para>
/// <para>__toFile : Xcode上で移動後のファイル名</para>
/// <para></para>
/// <para>REMOVE</para>
/// <para>(Xcode上からファイルを削除する)</para>
/// <para>_fromDir : Xcode上のディレクトリ</para>
/// <para>fromFile : Xcode上のファイル名</para>
/// <para>___toDir : -</para>
/// <para>__toFile : -</para>
/// </summary>
/// <param name="type">Type.</param>
/// <param name="fromDir">From dir.</param>
/// <param name="fromFile">From file.</param>
/// <param name="toDir">To dir.</param>
/// <param name="toFile">To file.</param>
/// <param name="compileFlags">Compile Flags.</param>
public FileParam(FileEditType type, string fromDir, string fromFile, string toDir = null, string toFile = null, string compileFlags = null, bool codeSignOnCopy = false, bool removeHeadersOnCopy = false)
{
if (type != FileEditType.REMOVE)
{
var param = "";
var isNull = false;
if (toDir == null)
{
param += "toDir";
isNull = true;
}
if (toFile == null)
{
if (isNull)
{
param += ", ";
}
param += "toFile";
}
if (isNull)
{
throw new System.ArgumentNullException(param, "If type is not REMOVE, you must set toXXX parameter!");
}
}
if (toFile == null)
{
toFile = fromFile;
}
if (toDir == null)
{
toDir = fromDir;
}
this.Type = type;
this.FromDirPath = fromDir;
this.FromFileName = fromFile;
this.ToDirPath = toDir;
this.ToFileName = toFile;
this.CompileFlags = compileFlags;
this.CodeSignOnCopy = codeSignOnCopy;
this.RemoveHeadersOnCopy = removeHeadersOnCopy;
}
/// <summary>
/// ログを作成.
/// </summary>
public string CreateLog()
{
var log = "[File:";
switch (Type)
{
case FileEditType.ADD:
log += "Add]" + "\n\tUnity file: " + CombinePath(FromDirPath, FromFileName) + "\n\tXcode file: " + CombinePath(ToDirPath, ToFileName + "\n\tCompile flags: " + CompileFlags);
break;
case FileEditType.MOVE:
log += "Move]" + "\n\tXC before file: " + CombinePath(FromDirPath, FromFileName) + "\n\tXC after file: " + CombinePath(ToDirPath, ToFileName + "\n\tCompile flags: " + CompileFlags);
break;
case FileEditType.REMOVE:
log += "Delete]" + "\n\tDelete file: " + CombinePath(FromDirPath, FromFileName);
break;
}
return log;
}
}
/// <summary>
/// 設定されているパラメータのログ。
/// </summary>
/// <returns>The parameter log.</returns>
public override string GetParamLog()
{
var log = "";
foreach (FileParam param in m_params)
{
log += param.CreateLog() + "\n";
}
return log;
}
/// <summary>
/// 設定の編集を行う
/// </summary>
/// <param name="pbxProj">Pbx projct.</param>
public override void Edit(ref PBXProject pbxProj)
{
foreach (FileParam param in m_params)
{
switch (param.Type)
{
case FileEditType.ADD:
{
// ファイルを追加する
AddFile(ref pbxProj, param);
break;
}
case FileEditType.MOVE:
{
// ファイルのリネームや移動
MoveFile(ref pbxProj, param);
break;
}
case FileEditType.REMOVE:
{
// ファイルの削除
RemoveFile(ref pbxProj, param);
break;
}
}
}
}
/// <summary>
/// Unity上にはあるが、プロジェクトに追加されていないファイルをXcodeプロジェクトに追加する。
/// </summary>
/// <param name="pbxProj">Pbx proj.</param>
/// <param name="param">Parameter.</param>
private void AddFile(ref PBXProject pbxProj, FileParam param)
{
// UnityのファイルをXcodeにコピーする
var unityPath = CombinePath(UnityEngine.Application.dataPath, param.FromDirPath, param.FromFileName);
var xcodePath = CombinePath(m_xcodePath, param.ToDirPath, param.ToFileName);
CopyFile(unityPath, xcodePath);
var addPath = CombinePath(param.ToDirPath, param.ToFileName);
AddFileProc(ref pbxProj, addPath, param);
}
/// <summary>
/// Xcodeにファイルを追加する
/// </summary>
/// <param name="pbxProj">Pbx proj.</param>
/// <param name="addPath">Add path.</param>
/// <param name="compileFlag">Compile flag.</param>
private void AddFileProc(ref PBXProject pbxProj, string addPath, FileParam param)// string compileFlag)
{
// ファイル参照をプロジェクトに追加
var fileGuid = pbxProj.AddFile(addPath, addPath);
// プロジェクトの設定(BuildPhase)に追加
foreach (var guid in GetProjectGuids(pbxProj))
{
if (param.CodeSignOnCopy) PBXProjectExtensions.AddFileToEmbedFrameworks(pbxProj, guid, fileGuid);
pbxProj.AddFileToBuildWithFlags(guid, fileGuid, param.CompileFlags);
}
}
/// <summary>
/// Xcodeのファイルを移動(リネーム)する
/// </summary>
/// <param name="pbxProj">Pbx proj.</param>
/// <param name="param">Parameter.</param>
private void MoveFile(ref PBXProject pbxProj, FileParam param)
{
var beforePath = CombinePath(param.FromDirPath, param.FromFileName);
var afterPath = CombinePath(param.ToDirPath, param.ToFileName);
// 既存のファイルを削除
RemoveFileProc(ref pbxProj, beforePath);
// 既存のファイルのリネーム
MoveFile(CombinePath(m_xcodePath, beforePath), CombinePath(m_xcodePath, afterPath));
// リネーム後ファイルの追加
AddFileProc(ref pbxProj, afterPath, param);
}
/// <summary>
/// Xcodeに追加されているファイルの削除(物理削除は行わない)
/// </summary>
/// <param name="pbxProj">Pbx proj.</param>
/// <param name="param">Parameter.</param>
private void RemoveFile(ref PBXProject pbxProj, FileParam param)
{
var removePath = CombinePath(param.FromDirPath, param.FromFileName);
RemoveFileProc(ref pbxProj, removePath);
}
/// <summary>
/// Xcodeに追加されているファイルの削除(物理削除は行わない)
/// </summary>
/// <param name="pbxProj">Pbx proj.</param>
/// <param name="removePath">Remove path.</param>
private void RemoveFileProc(ref PBXProject pbxProj, string removePath)
{
if (!pbxProj.ContainsFileByProjectPath(removePath)) return;
var fileGuid = pbxProj.FindFileGuidByProjectPath(removePath);
foreach (var guid in GetProjectGuids(pbxProj))
{
pbxProj.RemoveFileFromBuild(guid, fileGuid);
}
pbxProj.RemoveFile(fileGuid);
}
/// <summary>
/// ファイルの親ディレクトリを作成する。
/// </summary>
/// <param name="filePath">File path.</param>
public static void CreateParentDirectory(string filePath)
{
var files = filePath.Split("/"[0]);
string path = null;
for (int i = 0; i < files.Length - 1; ++i)
{
path = path == null ? files[i] : path + "/" + files[i];
if (string.IsNullOrEmpty(path)) continue;
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}
}
}
/// <summary>
/// ファイルをコピーする.
/// </summary>
/// <param name="fromFile">From file.</param>
/// <param name="toFile">To file.</param>
public static void CopyFile(string fromFile, string toFile)
{
CreateParentDirectory(toFile);
FileUtil.CopyFileOrDirectory(fromFile, toFile);
}
/// <summary>
/// ファイルを移動(リネーム)する。
/// </summary>
/// <param name="fromFile">From file.</param>
/// <param name="toFile">To file.</param>
public static void MoveFile(string fromFile, string toFile)
{
CreateParentDirectory(toFile);
FileUtil.MoveFileOrDirectory(fromFile, toFile);
}
/// <summary>
/// パスの結合
/// </summary>
/// <returns>The path.</returns>
/// <param name="fileAndDir">File and dir.</param>
public static string CombinePath(params string[] fileAndDir)
{
string root = fileAndDir[0];
for (int i = 1; i < fileAndDir.Length; ++i)
{
root = Path.Combine(root, fileAndDir[i]);
}
return root;
}
/// <summary>
/// コンストラクタ
/// </summary>
/// <param name="parameters">Parameters.</param>
/// <param name="xcodePath">Xcode path.</param>
/// <param name="projectNames">Project names.</param>
public PBXParamFile(List<FileParam> parameters, string xcodePath, ProjectType projectType = ProjectType.Main) : base(projectType)
{
m_params = parameters;
m_xcodePath = xcodePath;
}
}
/// <summary>
/// Framework変更
/// </summary>
public class PBXParamFramework : PBXParam
{
/// <summary>
/// Framework設定
/// </summary>
private readonly Dictionary<string, int> m_framemworks;
/// <summary>
/// ログ用の文字列作成
/// </summary>
/// <returns>The parameter log.</returns>
public override string GetParamLog()
{
string log = "";
foreach (KeyValuePair<string, int> framework in m_framemworks)
{
log += "[Framework] " + framework.Key + ": " +
(
(framework.Value == -1) ? "Delete!!" :
(
(framework.Value == 1) ? "Optional" : "Required"
)
) + "\n";
}
return log;
}
/// <summary>
/// 設定の編集を行う
/// </summary>
/// <param name="pbxProj">Pbx projct.</param>
public override void Edit(ref PBXProject pbxProj)
{
IEnumerable<string> guids = GetProjectGuids(pbxProj);
foreach (string guid in guids)
{
foreach (KeyValuePair<string, int> framemwork in m_framemworks)
{
if (framemwork.Value == -1)
pbxProj.RemoveFrameworkFromProject(guid, framemwork.Key);
else
pbxProj.AddFrameworkToProject(guid, framemwork.Key, framemwork.Value == 1);
}
}
}
/// <summary>
/// コンストラクタ
///
/// new Dictionary<string, int>() {
/// { "value1", 0 }, // Required
/// { "value2", 1 }, // Optional
/// { "value3", -1 },// 削除
/// }
/// </summary>
/// <param name="framemworks">Framemworks.</param>
/// <param name="projectNames">Project names.</param>
public PBXParamFramework(Dictionary<string, int> framemworks, ProjectType projectType = ProjectType.Main) : base(projectType)
{
this.m_framemworks = framemworks;
}
}
/// <summary>
/// プロパティ変更
/// </summary>
public class PBXParamProperty : PBXParam
{
/// <summary>
/// プロパティ設定
/// </summary>
private readonly Dictionary<string, List<PropertyParams>> m_params;
/// <summary>
/// プロパティ設定項目
/// </summary>
public class PropertyParams
{
/// <summary> 設定を行うタイプ(Debug/Releaseなど) </summary>
public string ConfigType { get; private set; }
/// <summary> 追加する値</summary>
public string[] AddValues { get; private set; }
/// <summary> 削除する値</summary>
public string[] RemoveValues { get; private set; }
/// <summary> 既存の項目をむしして上書きするかどうか。</summary>
public bool ForceOverride { get; private set; }
/// <summary>
/// コンストラクタ
/// </summary>
/// <param name="configType">設定を行うコンフィグのタイプ.nullの場合はすべての設定に反映されます.</param>
/// <param name="addValue">追加する値の配列.</param>
/// <param name="removeValue">削除する値の配列.</param>
/// <param name="forceOverride">強制的に上書きを行うかどうか.</param>
public PropertyParams(string[] addValue, string[] removeValue = null, string configType = null, bool forceOverride = false)
{
this.ConfigType = configType;
this.AddValues = addValue;
this.RemoveValues = removeValue;
this.ForceOverride = forceOverride;
}
/// <summary>
/// 単一の値を全オプションに反映する用の簡易コンストラクタ
/// </summary>
/// <param name="addValue">追加する値</param>
/// <returns></returns>
public PropertyParams(string addValue) : this(new string[] { addValue }) { }
/// <summary>
/// ログの作成
/// </summary>
/// <returns>The log.</returns>
public string CraeteLog()
{
var add = "[";
for (int i = 0; AddValues != null && i < AddValues.Length; ++i)
{
add += AddValues[i];
if (AddValues.Length - 1 != i)
{
add += ",";
}
}
add += "]";
var remove = "[";
for (int i = 0; RemoveValues != null && i < RemoveValues.Length; ++i)
{
remove += RemoveValues[i];
if (RemoveValues.Length - 1 != i)
{
remove += ",";
}
}
remove += "]";
return "\n\tConfig Type: " + ConfigType + "\n\tadd values: " + add + "\n\tremove values: " + remove;
}
}
/// <summary>
/// コンフィグ設定のguidを取得
/// </summary>
/// <returns>The config guids.</returns>
/// <param name="pbxProj">Pbx proj.</param>
/// <param name="configName">Config name.</param>
private IEnumerable<string> GetConfigGuids(PBXProject pbxProj, string configName)
{
IEnumerable<string> projects = GetProjectGuids(pbxProj);
List<string> guids = new List<string>();
foreach (string guid in projects)
{
guids.Add(pbxProj.BuildConfigByName(guid, configName));
}
return guids;
}
/// <summary>
/// ログの作成
/// </summary>
/// <returns>The parameter log.</returns>
public override string GetParamLog()
{
var log = "";
foreach (KeyValuePair<string, List<PropertyParams>> kv in m_params)
{
foreach (PropertyParams param in kv.Value)
{
log += "[Property] " + kv.Key + ":" + param.CraeteLog() + "\n";
}
}
return log;
}
/// <summary>
/// 設定の編集を行う
/// </summary>
/// <param name="pbxProj">Pbx projct.</param>
public override void Edit(ref PBXProject pbxProj)
{
foreach (KeyValuePair<string, List<PropertyParams>> param in m_params)
{
var key = param.Key;
foreach (PropertyParams propertyItem in param.Value)
{
IEnumerable<string> guids = propertyItem.ConfigType == null ? GetProjectGuids(pbxProj) : GetConfigGuids(pbxProj, propertyItem.ConfigType);
// 既存設定を無視して上書き
if (propertyItem.ForceOverride)
{
int i = 0;
if (propertyItem.ConfigType == null)
{
foreach (string addValue in propertyItem.AddValues)
{
if (i == 0)
pbxProj.SetBuildProperty(guids, key, addValue);
else
pbxProj.AddBuildProperty(guids, key, addValue);
}
++i;
}
else
{
guids = GetConfigGuids(pbxProj, propertyItem.ConfigType);
foreach (string addValue in propertyItem.AddValues)
{
if (i == 0)
pbxProj.SetBuildPropertyForConfig(guids, key, addValue);
else
pbxProj.AddBuildPropertyForConfig(guids, key, addValue);
}
++i;
}
}
else
{
if (propertyItem.ConfigType == null)
{
pbxProj.UpdateBuildProperty(guids, key, propertyItem.AddValues, propertyItem.RemoveValues);
}
else
{
/*
* UpdateBuildPropertyForConfig( IEnumerator<string>, stirng, string[], string[] )
* は内部的に、UpdateBuildProperty( string, string, string[], string[] )をコールしており、
* UpdateBuildPropertyForConfig( string, string, string[], string[] )と挙動が異なるので、foreachでguidはループで指定する
*/
foreach (string guid in guids)
{
pbxProj.UpdateBuildPropertyForConfig(guid, key, propertyItem.AddValues, propertyItem.RemoveValues);
}
}
}
}
}
}
/// <summary>
/// コンストラクタ
/// </summary>
/// <param name="parameters">Parameters.</param>
/// <param name="projectNames">Project names.</param>
public PBXParamProperty(Dictionary<string, List<PropertyParams>> parameters, ProjectType projectType = ProjectType.Main) : base(projectType)
{
this.m_params = parameters;
}
/// <summary>
/// コンストラクタ string のみで簡易設定用
/// </summary>
/// <param name="parameters"></param>
/// <param name="projectType"></param>
/// <returns></returns>
public PBXParamProperty(Dictionary<string, string> parameters, ProjectType projectType = ProjectType.Main) : base(projectType)
{
m_params = new Dictionary<string, List<PropertyParams>>();
foreach (var param in parameters)
{
m_params[param.Key] = new List<PropertyParams> { new PropertyParams(param.Value) };
}
}
}
}
#endif
PlistEditor.cs
PlistEditor.cs
#if UNITY_IOS
/**
* @file PlistEditor.cs
* @brief plistの編集を行うクラス。
* @date $Date$
* @version $Rev$
* @author $Author$
*/
using UnityEditor.iOS.Xcode;
using System;
using System.IO;
using System.Collections.Generic;
namespace yyama2.Editor.XCProjEdit {
/// <summary>
/// plistの値を変更する。
///
///
/// 値の設定は、下記のように定義してください。
/// ※キーは任意の文字列です。
///
/// int 系のデータ
/// { "int", 1 },
/// boolean系の値
/// { "bool", true },
/// 文字列
/// { "string", "string value" },
/// 配列
/// { "list", new List<object>() { 1, 2, 3 } },
/// Dict
/// { "dict", new Dictionary<string, object>() {
/// { "value1", "string value" },
/// { "value2", 1 },
/// { "value3", true },
/// }
/// },
/// </summary>
public class PlistEditor {
/// <summary> Info.plistのパスを取得する</summary>
/// <param name="path"> Info.plistのあるフォルダパス</param>
/// <returns> Info.plistのファイルパス</returns>
public static string GetInfoPlistPath( string path )
{
return Path.Combine( path, "Info.plist" );
}
/// <summary>
/// plistを編集する。
/// </summary>
/// <param name="plistPath"> plistファイルパス</param>
/// <param name="values">追加する値.</param>
/// <param name="callClass">この関数を呼び出しているクラス.</param>
public static void EditPlist( string plistPath, Dictionary<string, object> values, Type callClass )
{
string className = "";
if( callClass != null )
{
className += callClass.Name;
}
UnityEngine.Debug.Log( "PlistEditor:" + className );
string log = "======================= PlistValue =======================\n";
UnityEngine.Debug.Log( "plistPath=>" + plistPath );
PlistDocument plist = new PlistDocument();
plist.ReadFromFile( plistPath );
foreach( KeyValuePair<string, object> value in values )
{
setValue( value.Key, value.Value, ref plist.root );
}
// Documentsフォルダを共有可能にする
plist.WriteToFile( plistPath );
log += className + "\n";
log += plistPath +"\n{";
foreach( var value in values )
{
CreateLog( value.Key, value.Value, 0, ref log );
}
log += "\n}\n" + "======================= PlistValue =======================";
UnityEngine.Debug.Log( log );
}
/// <summary>
/// 値をセットする
/// </summary>
/// <param name="key"> キー.</param>
/// <param name="value"> 値.</param>
/// <param name="dict"> Dictオブジェクト.</param>
private static void setValue( string key, object value, ref PlistElementDict dict )
{
bool validValue = true;
Type type = value.GetType();
// int .
if( type == typeof(int) )
{
dict.SetInteger( key, (int)value );
}
// bool .
else if( type == typeof(bool) )
{
dict.SetBoolean( key, (bool)value );
}
// string .
else if( type == typeof(string) )
{
dict.SetString( key, (string)value );
}
// list
else if( type == typeof(List<object>) )
{
PlistElementArray subArray;
if( !tryGetValue<PlistElementArray>( key, dict, out subArray ) )
{
subArray = dict.CreateArray( key );
}
List<object> list = (List<object>)value;
foreach( object val in list )
{
addValue( val, ref subArray );
}
}
// dictionary
else if( type == typeof(Dictionary<string, object>) )
{
PlistElementDict subDict;
if( !tryGetValue<PlistElementDict>( key, dict, out subDict ) )
{
subDict = dict.CreateDict( key );
}
Dictionary<string, object> dictionary = (Dictionary<string, object>)value;
foreach( var dictItem in dictionary )
{
setValue( dictItem.Key, dictItem.Value, ref subDict );
}
}
else validValue = false;
// invalid parameter
if( !validValue )
{
UnityEngine.Debug.LogError( "Plist Editor. Invalid Parameter => " + key );
}
}
/// <summary>
/// リストに値をセットする
/// </summary>
/// <param name="value">値.</param>
/// <param name="array">Arrayオブジェクト.</param>
private static void addValue( object value, ref PlistElementArray array )
{
Type type = value.GetType();
// int .
if( type == typeof(int) )
{
array.AddInteger( (int)value );
}
// bool .
else if( type == typeof(bool) )
{
array.AddBoolean( (bool)value );
}
// string .
else if( type == typeof(string) )
{
array.AddString( (string)value );
}
// list
else if( type == typeof(List<object>) )
{
PlistElementArray subArray = array.AddArray();
List<object> list = (List<object>)value;
foreach( object val in list )
{
addValue( val, ref subArray );
}
}
// dictionary
else if( type == typeof(Dictionary<string, object>) )
{
PlistElementDict subDict = array.AddDict();
Dictionary<string, object> dictionary = (Dictionary<string, object>)value;
foreach( var dictItem in dictionary )
{
setValue( dictItem.Key, dictItem.Value, ref subDict );
}
}
else
{
UnityEngine.Debug.LogError( "Add List Error!!" );
}
}
/// <summary>
/// dictオブジェクトから値を抽出する
/// </summary>
/// <returns><c>true</c>, if success to get, <c>false</c> otherwise.</returns>
/// <param name="key">Key.</param>
/// <param name="dict">Dictオブジェクト.</param>
/// <param name="val">Value.</param>
/// <typeparam name="T">The 1st type parameter.</typeparam>
private static bool tryGetValue<T>( string key, PlistElementDict dict, out T val ) where T : PlistElement
{
IDictionary<string, PlistElement> dictValue = dict.values;
PlistElement el;
val = null;
if( dictValue.TryGetValue( key, out el ) )
{
val = el as T;
}
return val != null;
}
/// <summary>
/// ログ様の文字列作成 .
/// </summary>
/// <param name="key">Key.</param>
/// <param name="value">Value.</param>
/// <param name="indent">Indent.</param>
/// <param name="log">Log.</param>
private static void CreateLog( string key, object value, int indent, ref string log )
{
++indent;
string indentTabs = "";
for( int i = 0; i < indent; ++i )
{
indentTabs += "\t";
}
log += "\n" + indentTabs + key + ":";
Type type = value.GetType();
// int .
if( type == typeof(int) )
{
log += value;
}
// bool .
else if( type == typeof(bool) )
{
log += value;
}
// string .
else if( type == typeof(string) )
{
log += "\"" + value + "\"";
}
// list
else if( type == typeof(List<object>) )
{
log += "[";
List<object> list = (List<object>)value;
for( int i = 0; i < list.Count; ++i )
{
CreateLog( "["+ i +"]", list[i], indent, ref log);
}
log += "\n" + indentTabs + "]";
}
// dictionary
else if( type == typeof(Dictionary<string, object>) )
{
Dictionary<string, object> dictionary = (Dictionary<string, object>)value;
log += "{";
foreach( var dictItem in dictionary )
{
CreateLog( dictItem.Key, dictItem.Value, indent, ref log );
}
log += "\n" + indentTabs + "}";
}
log += ",";
}
}
}
#endif