ios

本文深入探讨了iOS开发中的关键技术点,包括Swift语言特性、UIKit框架应用、App性能优化及实战项目经验分享,帮助开发者提升iOS应用开发能力。
摘要由CSDN通过智能技术生成
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEditor.SceneManagement;//编辑器模式下管理场景
using System.IO;
using System;
using System.Diagnostics;
using UnityEditor;

//服务器类型
public enum ServerType
{
    Local,
    QA,
    Alpha,
    Real,
    RealQA,
    OutDev
}

public class IOSBuilder : MonoBehaviour {

     static bool openExplorer = true;
    static string[] SCENES = FindEnabledEditorScenes();

#region Build IOS IPA
    //Unity编辑器扩展-菜单项
    [MenuItem("Tools/BuildIOS/测试包")]
    static void MenuItemBulidIOS()
    {
        BuildIOS(true,true,"",ServerType.QA,true);
    }

#endregion

    /// <summary>
    /// IOS本打包处理
    /// </summary>
    /// <param name="offlineMode">是否支持离线模式</param>
    /// <param name="projectOnly">仅导出工程不打包</param>
    /// <param name="platform">具体渠道</param>
    /// <param name="type">服务器类型</param>
    static void BuildIOS(bool offlineMode, bool projectOnly, string platform = "", ServerType type = ServerType.Alpha, bool svnUpdate = true)
    {
        // 更新并获取SVN版本号
        string applicationPath = Application.dataPath.Replace("/Assets", "");

        //更新svn 
        // if (svnUpdate)
        // {
        //     SVNUpdate(applicationPath);
        // }
        // string version = GetSVNVersion(applicationPath);
        // string svnVersionFilePath = applicationPath + "/Shells/svn_ver.txt";
        // FileStream svnVersionFile = new FileStream(svnVersionFilePath, FileMode.Create);
        // StreamWriter writer = new StreamWriter(svnVersionFile);
        // writer.Write(version);
        // writer.Flush();
        // writer.Close();
        // svnVersionFile.Close();

        //游戏版本号
        string version = "1.0.0";

        // 获取游戏版本号
        string versionFilePath = applicationPath + "/version.txt";
        FileStream versionFile = new FileStream(versionFilePath, FileMode.Open);
        StreamReader reader = new StreamReader(versionFile);
        string bundleVersion = reader.ReadLine();
        string shortVersion = bundleVersion.Substring(0, bundleVersion.LastIndexOf("."));
        reader.Close();
        versionFile.Close();

        // 修改NetworkController中的版本号
        // string prefabPath = "Assets/Prefabs/Common/NetworkController.prefab";
        // GameObject prefab = AssetDatabase.LoadAssetAtPath<GameObject>(prefabPath) as GameObject;
        // NetworkController netCtrl = prefab.GetComponent<NetworkController>();
        // if (netCtrl._clientVersion != bundleVersion)
        // {
        //     netCtrl._clientVersion = bundleVersion;
        //     EditorUtility.SetDirty(prefab);
        //     AssetDatabase.SaveAssets();
        // }

        // 设置输出目录名
        string dir_name = "xiaoxiong";
        dir_name = dir_name + (projectOnly ? "_proj" : "_ipa");
        dir_name = dir_name + (offlineMode ? "_offline" : "");
        switch (type)
        {
            case ServerType.Local:
                dir_name = dir_name + "_local";
                break;
            case ServerType.QA:
                dir_name = dir_name + "_qa";
                break;
            case ServerType.Real:
            case ServerType.RealQA:
                dir_name = dir_name + "_release";
                break;
        }
        dir_name = dir_name + "_" + version;
        dir_name = dir_name + (platform.Length > 0 ? "_" + platform : "");
        // 重设宏定义
        string macroDefine = "EXCEPT_LINE";
        macroDefine += ";ENCRYPT";
        // 设置应用信息
        PlayerSettings.companyName = "LongtuGame";
        PlayerSettings.productName = "小熊爱消除";
         switch (platform)
        {
            case "lemon":
                if(type != ServerType.Real){
                    PlayerSettings.applicationIdentifier = "com.longtugame.xxaxc.cj";
                }else{
                    PlayerSettings.applicationIdentifier = "com.longtugame.xxaxc";
                }
            macroDefine += ";PLATFORM_LemonAppStore";
                break;
             default:
                 PlayerSettings.applicationIdentifier = "com.longtugame.xxaxc";
                 break;
        }

        // 设置SDK测试平台信息
        //PlayerSettings.iOS.sdkVersion = projectOnly ? iOSSdkVersion.SimulatorSDK : iOSSdkVersion.DeviceSDK;
        //(为真机测试平台,否则打开上一句代码)
        PlayerSettings.iOS.sdkVersion = iOSSdkVersion.DeviceSDK;
        PlayerSettings.iOS.targetOSVersion = iOSTargetOSVersion.iOS_7_0;

        // 设置版本号(注意这里与安卓不同)
#if UNITY_5
        PlayerSettings.bundleVersion = bundleVersion;
        PlayerSettings.iOS.buildNumber = version;
#else
        PlayerSettings.bundleVersion = version;
        PlayerSettings.shortBundleVersion = bundleVersion;
#endif

        // 设置编译平台
        string target_dir = applicationPath + "/Packages/Xcode";
        BuildTarget buildTarget = BuildTarget.iOS;
        BuildTargetGroup targetGroup = BuildTargetGroup.iOS;

        // 创建目标目录
        if (!Directory.Exists(target_dir))
        {
            Directory.CreateDirectory(target_dir);
        }

        // 删除已有工程
        string target_path = target_dir + "/" + dir_name;
        DeleteDirectory(target_path);

        switch (type)
        {
            case ServerType.Local:
                macroDefine += ";PLATFORM_LOCAL";
                break;
            case ServerType.QA:
                macroDefine += ";PLATFORM_QA";
                break;
            case ServerType.Real:
            case ServerType.RealQA:
                macroDefine += ";RELEASE_MODE";
                break;
            default:
                break;
        }

        if(type != ServerType.Real){
        #if (UNITY_IOS || UNITY_IPHONE)
            UnityEngine.Debug.Log("-------Enabling USE_TestXG...");
            PlayerSettings.iOS.appleDeveloperTeamID = "SVH5KV22E6";
        #endif
        }else{
        #if (UNITY_IOS || UNITY_IPHONE)

            PlayerSettings.iOS.appleDeveloperTeamID = "UC3LC49W33";
        #endif
        #if UNITY_5
            PlayerSettings.iOS.buildNumber = string.Format("{0}1", bundleVersion);
        #else
            PlayerSettings.bundleVersion = string.Format("{0}1", bundleVersion);
        #endif
        }

        // 离线模式处理
        if (offlineMode)
        {
            // 设置离线模式支持
            macroDefine += ";OFFLINE_SUPPORT";
        }

        macroDefine += ";HOTFIX_ENABLE";

        // 刷新工程内的文件
        AssetDatabase.Refresh();

        // 设置宏定义
        PlayerSettings.SetScriptingDefineSymbolsForGroup(targetGroup, macroDefine);

        // 开始Build场景
        GenericBuild(SCENES, target_path, buildTarget, BuildOptions.None);

        // 重设宏定义
        PlayerSettings.SetScriptingDefineSymbolsForGroup(targetGroup, "EXCEPT_LINE");

        // 提交版本号文件
        if (isSVNFileModified(versionFilePath))
        {
            string logMsg = "update client version number to " + bundleVersion;
            SVNCommit(new string[] { versionFilePath }, logMsg);
        }

        // 打开输出目录
        if (projectOnly)
        {
            if (openExplorer)
            {
                Process.Start("open", target_path);
            }
            return;
        }

        // 创建IPA输出目录
        string outputDir = applicationPath + "/Packages/IOS/" + version + "/";
        if (!Directory.Exists(outputDir))
        {
            Directory.CreateDirectory(outputDir);
        }

        // 生成app的指令
        string iossdk = "iphoneos";
        //string command = "cd " + target_path + "\n";
        string appPath  = "";
        string command = "";
        string archiveName = dir_name + ".xcarchive";

        if (type == ServerType.Real)
        {
            //command += "xcodebuild clean -configuration Release -quiet || exit";
            //command += "xcodebuild clean build -sdk " + iossdk + " -target Unity-iPhone -configuration Release\n";

            // 生成ipa的指令
            //有可能需要修改app的路径名称
            //appPath = "build/Release-iphoneos/xxaxc.app";
            command = "build_ios_real.sh " + target_path + " " + outputDir + " " + archiveName;
        }
        else
        {
            //command += "xcodebuild clean -configuration Debug -quiet || exit";
            //command += "xcodebuild clean build -sdk " + iossdk + " -target Unity-iPhone -configuration Debug\n";

            // 生成ipa的指令
            //有可能需要修改app的路径名称
            //appPath = "build/Debug-iphoneos/xxaxc.app";
            command = "build_ios_qa_qa.sh " + target_path + " " + outputDir + " " + archiveName;
        }
        /*
        string ipaPath = ipaDir + "xiaoxiong";
        ipaPath = ipaPath + "_" + bundleVersion;
        ipaPath = ipaPath + (version.Length > 0 ? "." + version : "");
        ipaPath = ipaPath + (offlineMode ? "_offline" : "");
        switch (type)
        {
            case ServerType.Local:
                ipaPath = ipaPath + "_local";
                break;
            case ServerType.QA:
                ipaPath = ipaPath + "_qa";
                break;
            case ServerType.Real:
                ipaPath = ipaPath + "_release";
                break;
            default:
                break;
        }
        ipaPath = ipaPath + (platform.Length > 0 ? "_" + platform : "");
        ipaPath = ipaPath + "_" + version;
        ipaPath = ipaPath + ".ipa";
        command += "xcrun -sdk " + iossdk + " PackageApplication -v " + appPath + " -o " + ipaPath + "\n";

        // 打开输出目录
        if (openExplorer)
        {
            command += "open " + ipaDir + "\n";
        }

        // 写入脚本文件增加权限
        string shellPath = applicationPath + "/Packages/packIOS.sh";
        WriteText(shellPath, command);
        executeCommand("chmod", "+x " + shellPath);
        */
        // 重设宏定义
        PlayerSettings.SetScriptingDefineSymbolsForGroup(targetGroup, "EXCEPT_LINE;OFFLINE_SUPPORT;ENCRYPT;HOTFIX_ENABLE");

        // 重设包名
        PlayerSettings.applicationIdentifier = "com.longtugame.xiaoxiongaixiaochu";

        // 打开命令行执行脚本
        //executeCommand("/Applications/Utilities/Terminal.app/Contents/MacOS/Terminal", shellPath, false);
        //executeCommand("/Applications/Utilities/Terminal.app/Contents/MacOS/Terminal", command, true);
    }

    private static void executeCommand(string exe, string param, bool wait=true)
    {
        UnityEngine.Debug.Log("executeCommand " + param);
        using (Process process = Process.Start(exe, param))  
        {
            if (wait)
                process.WaitForExit();  
        }
    }

    /// <summary>
    /// 递归删除目录
    /// </summary>
    /// <param name="path">目录路径</param>
    private static void DeleteDirectory(string path)
    {
        if (!Directory.Exists(path))
        {
            return;
        }

        DirectoryInfo dirInfo = new DirectoryInfo(path);

        foreach (DirectoryInfo subInfo in dirInfo.GetDirectories())
        {
            DeleteDirectory(subInfo.FullName);
        }

        foreach (FileInfo fileInfo in dirInfo.GetFiles("*.*"))
        {
            fileInfo.Delete();
        }

        Directory.Delete(path, true);
    }

    /// <summary>
    /// 递归复制目录
    /// </summary>
    /// <param name="source">源路径</param>
    /// <param name="target">目标路径</param>
    /// <returns>复制的文件+创建的目录列表</returns>
    private static List<string> CopyDirectory(string source, string target)
    {
        List<string> modifiedPath = new List<string>();
        if (!Directory.Exists(target))
        {
            Directory.CreateDirectory(target);
            modifiedPath.Insert(0, target);
        }

        DirectoryInfo dirInfo = new DirectoryInfo(source);
        foreach (DirectoryInfo subInfo in dirInfo.GetDirectories())
        {
            List<string> paths = CopyDirectory(source + "/" + subInfo.Name, target + "/" + subInfo.Name);
            modifiedPath.InsertRange(0, paths);
        }

        foreach (FileInfo fileInfo in dirInfo.GetFiles("*.*"))
        {
            File.Copy(fileInfo.FullName, target + "/" + fileInfo.Name, true);
            modifiedPath.Insert(0, target + "/" + fileInfo.Name);
        }
        return modifiedPath;
    }

    /// <summary>
    /// 取得SVN版本号
    /// </summary>
    /// <param name="path">SVN文件夹路径</param>
    /// <returns></returns>
    private static string GetSVNVersion(string path)
    {
        if (EditorUserBuildSettings.selectedStandaloneTarget != BuildTarget.StandaloneWindows
            && EditorUserBuildSettings.selectedStandaloneTarget != BuildTarget.StandaloneWindows64)
        {
            using (Process process = new Process())
            {
                process.StartInfo.FileName = "svn";
                process.StartInfo.Arguments = "info " + path;

                process.StartInfo.UseShellExecute = false;
                process.StartInfo.CreateNoWindow = true;
                process.StartInfo.RedirectStandardOutput = true;
                process.Start();

                string output = process.StandardOutput.ReadToEnd();
                process.WaitForExit();
                process.Close();

                string version = string.Empty;
                string matchStr = "Revision: ";
                int len = matchStr.Length;

                int index1 = output.IndexOf(matchStr);
                int index2 = output.IndexOf("\n", index1);
                if (index1 > 0 && index2 > index1)
                {
                    version = output.Substring(index1 + len, index2 - index1 - len);
                }

                return version;
            }
        }
        else
        {
            using (Process process = new Process())
            {
                process.StartInfo.FileName = "SubWCRev.exe";
                process.StartInfo.Arguments = "\"" + path + "\"";

                process.StartInfo.UseShellExecute = false;
                process.StartInfo.CreateNoWindow = true;
                process.StartInfo.RedirectStandardOutput = true;
                process.Start();

                string output = process.StandardOutput.ReadToEnd();
                process.WaitForExit();
                process.Close();

                string version = string.Empty;
                string matchStr = "to revision ";
                int len = matchStr.Length;

                int index1 = output.IndexOf(matchStr);
                int index2 = output.IndexOf("\r\n", index1);
                if (index1 > 0 && index2 > index1)
                {
                    version = output.Substring(index1 + len, index2 - index1 - len);
                }
                //string version = @"2000";
                return version;
            } 
        }
    }

    /// <summary>
    /// 判断文件相对于SVN是否有修改
    /// </summary>
    /// <param name="path"></param>
    /// <returns></returns>
    private static bool isSVNFileModified(string path)
    {
        if (EditorUserBuildSettings.selectedStandaloneTarget != BuildTarget.StandaloneWindows
            && EditorUserBuildSettings.selectedStandaloneTarget != BuildTarget.StandaloneWindows64)
        {
            using (Process process = new Process())
            {
                process.StartInfo.FileName = "svn";
                process.StartInfo.Arguments = "st " + path;

                process.StartInfo.UseShellExecute = false;
                process.StartInfo.CreateNoWindow = true;
                process.StartInfo.RedirectStandardOutput = true;
                process.Start();

                string output = process.StandardOutput.ReadToEnd();
                process.WaitForExit();
                process.Close();

                return output.IndexOf("M ") == 0;
            }
        }
        else
        {
            using (Process process = new Process())
            {
                process.StartInfo.FileName = "SubWCRev.exe";
                process.StartInfo.Arguments = "\"" + path + "\"";

                process.StartInfo.UseShellExecute = false;
                process.StartInfo.CreateNoWindow = true;
                process.StartInfo.RedirectStandardOutput = true;
                process.Start();

                string output = process.StandardOutput.ReadToEnd();
                process.WaitForExit();
                process.Close();

                return output.IndexOf("Local modifications found") > 0;
                //return false;
            }
        }
    }

    private static void SVNUpdate(string path)
    {
        if (EditorUserBuildSettings.selectedStandaloneTarget != BuildTarget.StandaloneWindows
            && EditorUserBuildSettings.selectedStandaloneTarget != BuildTarget.StandaloneWindows64)
        {
            using (var process = new Process())
            {
                process.StartInfo.FileName = "svn";
                process.StartInfo.Arguments = "update " + Application.dataPath.Replace("/Assets", "");

                process.StartInfo.UseShellExecute = false;
                process.StartInfo.CreateNoWindow = true;
                process.StartInfo.RedirectStandardOutput = true;
                process.Start();

                using (StreamReader reader = process.StandardOutput)
                {
                    string line = reader.ReadLine();
                    while (line != null && line.Length > 0)
                    {
                        UnityEngine.Debug.Log(line);
                        line = reader.ReadLine();
                    }
                }
                process.WaitForExit();
            }
        }
        else
        {
            string arguments = "/command:update /path:\"" + path + "\" /closeonend:2";
            Process process = Process.Start("TortoiseProc.exe", arguments);
            process.WaitForExit();
        }
        AssetDatabase.Refresh();
    }

    private static void SVNCommit(string[] filelist, string logmsg)
    {
        Process process = null;
        if (EditorUserBuildSettings.selectedStandaloneTarget != BuildTarget.StandaloneWindows
                && EditorUserBuildSettings.selectedStandaloneTarget != BuildTarget.StandaloneWindows64)
        {
            string pathlist = string.Empty;
            for (int n = 0; n < filelist.Length; n++)
            {
                pathlist += "\"" + filelist[n] + "\" ";
            }

            string arguments = "commit -m \"" + logmsg + "\" " + pathlist;
            UnityEngine.Debug.Log(arguments);
            process = Process.Start("svn", arguments);
        }
        else
        {
            string pathlist = string.Empty;
            for (int n = 0; n < filelist.Length; n++)
            {
                if (n > 0) pathlist += "*";
                pathlist += filelist[n];
            }

            string arguments = "/command:commit /path:\"" + pathlist + "\"";
            arguments += " /logmsg:\"" + logmsg + "\" /closeonend:2";
            process = Process.Start("TortoiseProc.exe", arguments);
        }
        process.WaitForExit();
    }

    private static void ReplaceInFile(string filePath, string origin, string dest)
    {
        FileStream fileStream = new FileStream(filePath, FileMode.Open);
        byte[] buffer = new byte[fileStream.Length];
        fileStream.Read(buffer, 0, (int)fileStream.Length);
        fileStream.Close();

        string fileContent = System.Text.Encoding.Default.GetString(buffer);
        fileContent = fileContent.Replace(origin, dest);
        buffer = System.Text.Encoding.Default.GetBytes(fileContent);
        fileStream = new FileStream(filePath, FileMode.Truncate);
        fileStream.Write(buffer, 0, buffer.Length);
        fileStream.Close();
    }

    private static void WriteText(string filePath, string content)
    {
        byte[] buffer = System.Text.Encoding.Default.GetBytes(content);
        FileStream fileStream = File.Exists(filePath) 
            ? new FileStream(filePath, FileMode.Truncate)
            : new FileStream(filePath, FileMode.OpenOrCreate);
        fileStream.Write(buffer, 0, buffer.Length);
        fileStream.Close();
    }

    private static string[] FindEnabledEditorScenes()
    {
        List<string> EditorScenes = new List<string>();
        foreach (EditorBuildSettingsScene scene in EditorBuildSettings.scenes)
        {
            if (!scene.enabled) continue;
            EditorScenes.Add(scene.path);
        }
        return EditorScenes.ToArray();
    }

    static void GenericBuild(string[] scenes, string target_dir, BuildTarget build_target, BuildOptions build_options)
    {
        if (EditorUserBuildSettings.activeBuildTarget != build_target)
        {
            EditorUserBuildSettings.SwitchActiveBuildTarget(build_target);
        }

        string res = BuildPipeline.BuildPlayer(scenes, target_dir, build_target, BuildOptions.None);
        if (res.Length > 0)
        {
            throw new Exception("BuildPlayer failure: " + res);
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值