びぼうろくってみんなやってる

みんなやってるからぼくもやる

ScriptableObjectを使ってBuildProfileを簡単に作って、保存して、ビルド時に使い分けられるようにしたかったときのこと

  • ScriptableObjectでPlayerSettingsに入れる値を保存する
  • ただの箱
  • これを継承した各プラットフォーム用のProfileClassを作成
  • androidのKeyStoreName等
public class BuildProfile : ScriptableObject
{
  public string artifactName;//生成ファイルの名前
  public string bundleIdentifier;
  public string bundleVersion;
  public string productName;
  public string companyName;
  public bool release;
  public List<string> defineSymbols;
  public string iconPath;
  public int accelerometerFrequency;
  public List<string> ignorePaths;//どけときたいフォルダ
}
  • EditorWindowで簡単に扱えるようにしたい
  • BuildProfileのリストを持ち、Build実行や、中身の確認をするEditorWindowを開くためのWindow
public class ProfileWindow : EditorWindow
{
  [MenuItem("File/BuildProfiles")]
  static void Init()
  {
    GetWindow<ProfileWindow>("BuildProfiles");
  }

  void OnGUI()
  {
    //例にアンドロイド.
    isAndroidFoldOut = EditorGUILayout.Foldout(isAndroidFoldOut, "Android");

    if(isAndroidFoldOut)
    {
      EditorGUI.indentLevel++;
      foreach(var androidProfile in androidProfiles)
      {
        if(androidProfile == null) { RefreshBuildProfiles(); return; }
        ButtonLayout(androidProfile, BuildTarget.Android);
      }
      AddNewBuildProfileLayout(BuildTarget.Android);
      EditorGUI.indentLevel--;
    }
    GUILayout.EndVertical();
  }

  void ButtonLayout(BuildProfile buildProfile, BuildTarget buildTarget)
  {
    EditorGUILayout.BeginHorizontal();
    EditorGUILayout.LabelField(buildProfile.name);
    if(GUILayout.Button("Select"))
    {
      EditorGUIUtility.PingObject(buildProfile);
      Selection.objects = new[] { buildProfile };
    }
    if(GUILayout.Button("Build"))
    {
      Build(buildProfile, buildTarget);
    }
    EditorGUILayout.EndHorizontal();
  }
}
  • BuildProfileの中身を見るEditorWindowも欲しさ
    • PlayerSettingsの値と見比べて、違うなら強調表示するやつがほしかった
      • いわゆるPlaceHolder
    • それぞれのプラットフォームに合わせて継承したクラスも作る
public class ProfileEditor : EditorWindow
{
  public override void OnInspectorGUI()
  {
    EditorGUI.BeginChangeCheck();
    PropertyLayouter();
    ButtonLayouter();

    if(EditorGUI.EndChangeCheck())
    {
      EditorUtility.SetDirty(buildProfile);
    }
  }

  protected virtual void PropertyLayouter()
  {
    buildProfile.artifactName = PlaceHolderTextField("artifactName",buildProfile.artifactName,buildProfile.name);

    //以下それぞれのプロパティ書いていく
  }
  //このWindowでもビルドしたり、Profile選択Window開きたい的な
  protected virtual void ButtonLayouter()
  {
    if(GUILayout.Button("Open Window"))
    {
      EditorWindow.GetWindow<ProfileWindow>("BuildProfiles");
    }

    if(GUILayout.Button("Build " + buildTargetGroup.ToString()))
    {
      Build();
      GUIUtility.ExitGUI();
    }
  }

  protected string PlaceHolderTextField(string propertyName, string input, string placeHolder)
  {
    GUI.SetNextControlName(propertyName);
    if(!string.IsNullOrEmpty(input) || GUI.GetNameOfFocusedControl() == propertyName)
    {
      return EditorGUILayout.TextField(propertyName, input);
    }
    EditorGUILayout.TextField(propertyName, placeHolder, defaultStyle);

    return input;
  }
}
  • BuildPipeline.BuildPlayer()
  • ビルド中にScriptableObjectのインスタンスが破棄されるのでScriptableObjectにバックアップをとっておくとかはできない。

  • でもPlayerSettingsはバックアップを取りたい

  • ので、全部コピー。
using System.IO;

public class Builder
{
  const string PlayerSettingsPath = "ProjectSettings/ProjectSettings.asset";
  const string BackupPlayerSettingsPath = "Temp/BackupProjectSettings.asset";

  public void BuildWithProfile(BuildProfile profile)
  {
    //他にもapk等の保存先を作るとかする

    BackupProjectSettings();//バックアップ
    SetProfile();//BuildProfile適用
    Build();//実行
    RestorePlayerSetting();//もとに戻す

    //バージョニングとかもする
  }

  void BackupCurrentPlayerSetting()
  {
    if(!File.Exists(PlayerSettingsPath)) { Debug.Log("not Exist"); return; }
    File.Copy(PlayerSettingsPath, BackupPlayerSettingsPath, true);
  }
  void SetProfile()
  {
    //PlayerSettingsにBuildProfileを入れる処理
  }

  void Build()
  {
      //BuildPipeline.BuildPlayer()
  }

  void RestorePlayerSetting()
  {
    File.Copy(BackupPlayerSettingsPath, PlayerSettingsPath, true);
    File.Delete(BackupPlayerSettingsPath);
    AssetDatabase.Refresh();
    }
}

そういった次第だった