Unityでビルド後に自動でRomをアップロードする拡張

Unityで作ったAndroid用のRomを他の人にテストプレイしてもらうときに、FTPツールを使っていちいちアップロードしていたのだけど、それがいちいちめんどくさかった。そこで自動で行うようにしてみました。

c#FTPを利用するのは以下を参考にしました。
Simple C# FTP Class - CodeProject
(元記事のupload関数は一部間違っている部分があるので修正が必要です。)

後はUnityのEditor拡張とかの仕方を調べて作ってみました。

下に載せたソース2つをEditorフォルダに入れて、PreferenceでURL(例:ftp://wkpn@wkpn.sakura.ne.jp/www/Output/)とユーザー名とパスワードを設定すると、Androidロムが出来上がった時に指定されたURLにUploadします。

using UnityEngine;
using UnityEditor;
using UnityEditor.Callbacks;

public class RomUploader {

	private const string cKeyIsFtpUpload = "KeyFtpUpload";
	static bool IsFtpUpload {
		get {
			string value = EditorUserSettings.GetConfigValue (cKeyIsFtpUpload);
			return!string.IsNullOrEmpty (value) && value.Equals ("True");
		}
		set {
			EditorUserSettings.SetConfigValue (cKeyIsFtpUpload, value.ToString ());
		}
	}

	private const string cKeyFTPURL = "KeyFTPURL";
	static string FTPURL {
		get {
			return EditorUserSettings.GetConfigValue (cKeyFTPURL);
		}
		set {
			EditorUserSettings.SetConfigValue(cKeyFTPURL, value);
		}
	}

	private const string cKeyFTPUserName = "KeyFTPUserName";
	static string UserName {
		get {
			return EditorUserSettings.GetConfigValue (cKeyFTPUserName);
		}
		set {
			EditorUserSettings.SetConfigValue(cKeyFTPUserName, value);
		}
	}

	private const string cKeyFTPPassword = "KeyFTPPassword";
	static string FTPPass {
		get {
			return EditorUserSettings.GetConfigValue (cKeyFTPPassword);
		}
		set {
			EditorUserSettings.SetConfigValue(cKeyFTPPassword, value);
		}
	}

	[PreferenceItem("Rom Upload")] 
	static void OnGUI()
	{
		IsFtpUpload = EditorGUILayout.BeginToggleGroup("Android Rom FTP Upload", IsFtpUpload);
        FTPURL = EditorGUILayout.TextField("FTP URL", FTPURL);
        UserName = EditorGUILayout.TextField("User Name", UserName);
        FTPPass = EditorGUILayout.PasswordField("Password", FTPPass);
		EditorGUILayout.EndToggleGroup();
    }

    [PostProcessBuildAttribute(1)]
    static void OnPostprocessBuild(BuildTarget target, string pathToBuiltProject) {
        Debug.Log( pathToBuiltProject );
        if( IsFtpUpload )
        {
#if UNITY_ANDROID
            FTPUploader ftp = new FTPUploader(FTPURL, UserName, FTPPass);

            string filename = System.IO.Path.GetFileName( pathToBuiltProject );
            ftp.Upload(filename, pathToBuiltProject);

            ftp = null;// Release Resources
#endif
        }
    }

}
using UnityEngine;
using System;
using System.IO;
using System.Net;

class FTPUploader
{
    private string host = null;
    private string user = null;
    private string pass = null;

    private FtpWebRequest ftpRequest = null;
    private Stream        ftpStream  = null;

    private const int bufferSize = 2048;

    public FTPUploader(string hostIP, string userName, string password) { host = hostIP; user = userName; pass = password; }

    public void Upload(string remote_file, string local_file)
    {
        try
        {
            /* Create an FTP Request */
            ftpRequest = (FtpWebRequest)FtpWebRequest.Create(host + "/" + remote_file);
            /* Log in to the FTP Server with the User Name and Password Provided */
            ftpRequest.Credentials = new NetworkCredential(user, pass);
            /* When in doubt, use these options */
            ftpRequest.UseBinary = true;
            ftpRequest.UsePassive = true;
            ftpRequest.KeepAlive = true;
            /* Specify the Type of FTP Request */
            ftpRequest.Method = WebRequestMethods.Ftp.UploadFile;
            /* Establish Return Communication with the FTP Server */
            ftpStream = ftpRequest.GetRequestStream();
            /* Open a File Stream to Read the File for Upload */
            FileStream localFileStream = new FileStream(local_file, FileMode.Open);
            /* Buffer for the Downloaded Data */
            byte[] byteBuffer = new byte[bufferSize];
            int bytesSent = localFileStream.Read(byteBuffer, 0, bufferSize);
            /* Upload the File by Sending the Buffered Data Until the Transfer is Complete */
            try
            {
                while (bytesSent != 0)
                {
                    ftpStream.Write(byteBuffer, 0, bytesSent);
                    bytesSent = localFileStream.Read(byteBuffer, 0, bufferSize);
                }
            }
            catch (Exception ex) 
            { 
                Debug.Log(ex.ToString()); 
            }
            /* Resource Cleanup */
            localFileStream.Close();
            ftpStream.Close();
            ftpRequest = null;
        }
        catch (Exception ex)
        {
            Debug.Log(ex.ToString()); 
        }
        return;
    }
} 
今回学んだことリスト
  • EditorUserSettingsでプロジェクト固有のデータを保存できる
  • PostProcessBuildAttribute属性をstatic関数に付与すると、その関数はビルド後に処理が走る
  • PostProcessBuildAttributeの引数は実行順
  • PreferenceItem属性を付与することで、Preferenceに設定を追加できる
  • EditorGUILayout.〜でGUIを作れる
  • EditorGUILayout.BeginToggleGroupとEditorGUILayout.EndToggleGroup()で囲むことで、その間に記載したGUIチェックボックスでOn/Offできる。