【IOS自动化解放双手系列一】unity3D导出xcode 工程并配置各种权限

打包是程序员必经之路。如何实现自动化是一个程序员的基本素质。(都是因为我懒,哈哈哈)。
使用环境 :unity3D 2017.4.7 Mac Pro
打包分一下几个部分 :
1、unity3D导出xcode 工程
2、设置xcode配置及各种sdk配置
3、命令行打包
4、上传蒲公英
5、上传bugly
【IOS自动化解放双手系列一】unity3D导出xcode 工程并配置各种权限
【IOS自动化解放双手系列二】命令行打IPA包和上传蒲公英
【IOS自动化解放双手系列三】上传bugly
接下来开始正式看代码

1、unity3D导出xcode 工程
我们使用assetbundle打包所以需要先打ab包 让配置相关服务器文件,在进行导出 代码如下

   public enum BUILDTYPE {
        QA,
        PREFE,
        REALSE
    }
    private static BUILDTYPE currenBulidType = BUILDTYPE.REALSE;
    public static void ExportIOSProject(BUILDTYPE uILDTYPE) {
        currenBulidType = uILDTYPE;
        EditorUserBuildSettings.SwitchActiveBuildTarget(BuildTargetGroup.iOS, BuildTarget.iOS);
        AssetDatabase.Refresh();
        MoveGameConfig(uILDTYPE);
        string shellPath = Application.dataPath.Replace("Assets", "Build/iOS/");
        //step1.打包资源。通过AssetBundleGraph 生成Build AssetsBundles
        BuildAssetsBundles();
        UnityEngine.Debug.Log("step1 Finished!!!");
        //Step2.移除无关文件,为Export IOS 工程做准备,调用shell脚本
        RunShell(shellPath + "RemoveFromUnity.sh");
        AssetDatabase.Refresh();
        UnityEngine.Debug.Log("step2 Finished!!!");
        //Step3.导出Apple 真机工程
        ExportAppleProject(iOSSdkVersion.DeviceSDK);
        UnityEngine.Debug.Log("step3 Finished!!!");
        //Step4.删除临时文件,调用shell脚本
        RunShell(shellPath + "RecoverUnity.sh");
        UnityEngine.Debug.Log("step4 Finished!!!");

        PlayerSettings.applicationIdentifier = "com.XXXX.XXX";
        AssetDatabase.Refresh();
    }

    public static void ExportAppleProject(iOSSdkVersion sdk) {
        List<string> scenes = new List<string>();
        foreach (EditorBuildSettingsScene scene in EditorBuildSettings.scenes) {
            if (!scene.enabled)
                continue;
            scenes.Add(scene.path);
        }
        bool isQA = false;
        switch (currenBulidType) {
            case BUILDTYPE.QA:
            case BUILDTYPE.PREFE:
                isQA = true;
                PlayerSettings.applicationIdentifier = "com.XXXX.XXX";
                break;
            case BUILDTYPE.REALSE:
                PlayerSettings.applicationIdentifier = "com.XXXX.XXX";
                isQA = false;
                break;
        }
        EditorUserBuildSettings.development = isQA;

        PlayerSettings.iOS.sdkVersion = sdk;
        PlayerSettings.iOS.buildNumber = GetVersion().ToString();
        //EditorUserBuildSettings.target
        BuildOptions buildOption = BuildOptions.None;
        string res = BuildPipeline.BuildPlayer(scenes.ToArray(), PathUtils.CombinePath("Build", ToolsFunctions.GetPlatformDefines(), "Project", sdk.ToString()), BuildTarget.iOS, buildOption);
        if (res.Length > 0) {
            throw new Exception("BuildPlayer failure : " + res);
        }
    }


 //=====================================公共函数=======================================
    private static void BuildAssetsBundles() {
        UnityEngine.AssetBundles.GraphTool.BatchBuildWindow.Open();
        UnityEngine.AssetBundles.GraphTool.BatchBuildWindow.BuildFromMenu();
    }

    private static void RunShell(string shellFile) {
        //      Thread thread = new Thread(new )
        //为了可以重试多线程所以加了一层
        UnityRunShell(shellFile);
    }

    private static void UnityRunShell(string shellFile) {
        Process process = new Process();
        process.StartInfo.FileName = shellFile;
        //      process.StartInfo.Arguments = "";
        process.StartInfo.UseShellExecute = false;
        process.StartInfo.ErrorDialog = true;
        process.StartInfo.CreateNoWindow = false;
        process.Start();
        process.WaitForExit();
        process.Close();
    }

    private static int GetVersion(){
        return ClientVersion.GetIncrementBundleVersion();
    }

    private static void MoveGameConfig(BUILDTYPE uILDTYPE ){
        string path = PathUtils.CombinePath(Application.dataPath,"../GameConfig/gameRealse.xml");

        switch(uILDTYPE){
            case BUILDTYPE.QA:
                path = PathUtils.CombinePath(Application.dataPath,"../GameConfig/gameQA.xml");
                break;
            case BUILDTYPE.PREFE:
                path = PathUtils.CombinePath(Application.dataPath,"../GameConfig/gamePrefe.xml");
                break;
            case BUILDTYPE.REALSE:
                path = PathUtils.CombinePath(Application.dataPath,"../GameConfig/gameRealse.xml");
                break;
        }

        CopyConfig(path);
    }

    private static void CopyConfig(string path) {
        string targePath = PathUtils.CombinePath(PathUtils.GameConfigWWWPath, "game.xml");
        string configStr = FileUtils.ReadAllText(path);
        if (string.IsNullOrEmpty(configStr)) {
            Client.LogManager.LogError("配置信息有误请查看后重新写入");
        }
        FileUtils.WriteAllText(targePath, configStr);
        Client.LogManager.Log("copy GameConfig finish");
    }

2、设置xcode配置及各种sdk配置
分一下几部分:
添加类库
框架的搜索追加设置
设置推送权限配置XXXXX.entitlements文件
unity修改oc代码

#if (UNITY_IOS || UNITY_IPHONE)
using UnityEngine;
using UnityEditor;
using UnityEditor.Callbacks;
using UnityEditor.iOS.Xcode;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System;
using System.Linq;
using System.Diagnostics;
using CDBGUnity;


public class CDBGPluginBuilder : MonoBehaviour {
    public static bool isUseTestXG = false;
    public static bool enableIosAppController = true;
    [PostProcessBuildAttribute(6)]
    static void onPostProcessBuild(BuildTarget buildTarget, string path) {
        UnityEngine.Debug.Log("PostProcessBuild   Start");
        if (buildTarget == BuildTarget.iOS) {
            // project path
            string projectPath = Path.Combine(path, "Unity-iPhone.xcodeproj/project.pbxproj");

            // xcodeproj
            PBXProject proj = new PBXProject();
            proj.ReadFromString(File.ReadAllText(projectPath));

            // target
            string target = PBXProject.GetUnityTargetName();

            target = proj.TargetGuidByName(target);
            UnityEngine.Debug.Log(">>>>target: " + target + "path :" + path);

            // Add System Frameworks
            //UnityEngine.Debug.Log(">>>>>Adding system frameworks to xcodeproj...");

            //proj.AddFrameworkToProject(target, "CoreText.framework", false);
            //proj.AddFrameworkToProject(target, "MediaPlayer.framework", false);
            proj.AddFrameworkToProject(target,"AgoraSigKit.framework",false);

            // Macro 
            //proj.AddBuildProperty(target, "GCC_PREPROCESSOR_DEFINITIONS", "");
            // 信鸽相关
            //string[] macros = { "USE_TestXG=1" };
            //if (isUseTestXG) {
            //    UnityEngine.Debug.Log("Enabling USE_TestXG...");
            //    proj.UpdateBuildProperty(target, "GCC_PREPROCESSOR_DEFINITIONS", macros, null);
            //} else {
            //    UnityEngine.Debug.Log("Disabling USE_TestXG...");
            //    proj.UpdateBuildProperty(target, "GCC_PREPROCESSOR_DEFINITIONS", null, macros);
            //}

            //proj.AddBuildProperty(target, "GCC_PREPROCESSOR_DEFINITIONS", "");
            //macros[0] = "USE_LGCAppController=1";
            //if (enableIosAppController) {
            //    UnityEngine.Debug.Log("Enabling USE_LGCAppController...");
            //    proj.UpdateBuildProperty(target, "GCC_PREPROCESSOR_DEFINITIONS", macros, null);
            //} else {
            //    UnityEngine.Debug.Log("Disabling USE_LGCAppController...");
            //    proj.UpdateBuildProperty(target, "GCC_PREPROCESSOR_DEFINITIONS", null, macros);
            //}

            //UnityEngine.Debug.Log("Setting up linker flags...");
            //string[] linkerFlagsToAdd = { "-ObjC", "-force_load", "$(PROJECT_DIR)/Frameworks/Plugins/iOS/LongtuSDK/LTShareSDK.framework/LTShareSDK" };
            //proj.UpdateBuildProperty(target, "OTHER_LDFLAGS", linkerFlagsToAdd, null);

            ////设置报名 
            //if (isUseTestXG) {
            //    proj.SetBuildProperty(target, "CODE_SIGN_IDENTITY", "iPhone Developer: jin dingjun (M39LLSEB5V)");
            //    proj.SetBuildProperty(target, "PROVISIONING_PROFILE", "xxaxc_cj_dev_20170609");
            //} else {
            //    proj.SetBuildProperty(target, "CODE_SIGN_IDENTITY", "iPhone Distribution: Beijing Zhong Qing Long Tu Network Technology Co.,LTD. (UC3LC49W33)");
            //    proj.SetBuildProperty(target, "PROVISIONING_PROFILE", "xxaxc_dist_20170607");
            //}


            //proj.overwriteBuildSetting ("CODE_SIGN_IDENTITY", "iPhone Developer: Yu Song (XXXXXXXXXX)", "Release");
            //proj.overwriteBuildSetting ("CODE_SIGN_IDENTITY", "iPhone Developer: Yu Song (XXXXXXXXXX)", "Debug");
            /****** Game End**/

            //UnityEngine.Debug.Log(">>>>target :" + target + "path :" + path);
            // 框架的搜索追加设置XXXXX.entitlements
            //UnityEngine.Debug.Log(">>>>>LONGTU Setting up framework search paths...");
            //proj.SetBuildProperty(target, "FRAMEWORK_SEARCH_PATHS", "$(inherited)");
            //proj.AddBuildProperty(target, "FRAMEWORK_SEARCH_PATHS", "$(PROJECT_DIR)/Libraries/");
            //proj.AddBuildProperty(target, "FRAMEWORK_SEARCH_PATHS", "$(PROJECT_DIR)/Frameworks/");
            //proj.AddBuildProperty(target, "FRAMEWORK_SEARCH_PATHS", "$(PROJECT_DIR)/Frameworks/Plugins/iOS/");
            //proj.AddBuildProperty(target, "FRAMEWORK_SEARCH_PATHS", "$(PROJECT_DIR)/Frameworks/Plugins/iOS/LongtuSDK/");
            //proj.AddBuildProperty(target, "FRAMEWORK_SEARCH_PATHS", "$(PROJECT_DIR)/Frameworks/ArmorSDK/Plugins/iOS/");

#if UNITY_5
            //proj.AddFileToBuild(target, proj.AddFile("usr/lib/libiconv.2.tbd", "Frameworks/libiconv.2.tbd", PBXSourceTree.Sdk));
            //proj.AddFileToBuild(target, proj.AddFile("usr/lib/libsqlite3.tbd", "Frameworks/libsqlite3.tbd", PBXSourceTree.Sdk));
            //proj.AddFileToBuild(target, proj.AddFile("usr/lib/libstdc++.6.0.9.tbd", "Frameworks/libstdc++.6.0.9.tbd", PBXSourceTree.Sdk));
            //proj.AddFileToBuild(target, proj.AddFile("usr/lib/libz.1.tbd", "Frameworks/libz.1.tbd", PBXSourceTree.Sdk));
            //proj.AddFileToBuild(target, proj.AddFile("usr/lib/libxml2.2.tbd", "Frameworks/libxml2.2.tbd", PBXSourceTree.Sdk));
            //proj.AddFileToBuild(target,proj.AddFile("usr/lib/libsqlite3.0.tbd"     ,"Frameworks/libsqlite3.0.tbd"     ,PBXSourceTree.Sdk));
            //proj.AddFileToBuild(target,proj.AddFile("usr/lib/libz.tbd"         ,"Frameworks/libz.tbd"         ,PBXSourceTree.Sdk));
            //string libiconvDylibPath = proj.AddFile("usr/lib/libiconv.2.dylib", "Frameworks/libiconv.2.dylib", PBXSourceTree.Sdk);
            ////proj.AddFileToBuild(target, libiconvDylibPath);
            //proj.RemoveFileFromBuild(target, libiconvDylibPath);
#else
            //proj.AddFileToBuild(target, proj.AddFile("usr/lib/libiconv.2.dylib", "Frameworks/libiconv.2.dylib", PBXSourceTree.Source));
            //proj.AddFileToBuild(target, proj.AddFile("usr/lib/libsqlite3.dylib", "Frameworks/libsqlite3.dylib", PBXSourceTree.Source));
            //proj.AddFileToBuild(target, proj.AddFile("usr/lib/libstdc++.6.0.9.dylib", "Frameworks/libstdc++.6.0.9.dylib", PBXSourceTree.Source));
            //proj.AddFileToBuild(target, proj.AddFile("usr/lib/libz.1.dylib", "Frameworks/libz.1.dylib", PBXSourceTree.Source));
            //proj.AddFileToBuild(target, proj.AddFile("usr/lib/libxml2.2.dylib", "Frameworks/libxml2.2.dylib", PBXSourceTree.Source));

            //proj.AddFileToBuild(target, proj.AddFile("usr/lib/libsqlite3.0.dylib", "Frameworks/libsqlite3.0.dylib", PBXSourceTree.Source));
            //proj.AddFileToBuild(target, proj.AddFile("usr/lib/libz.dylib", "Frameworks/libz.dylib", PBXSourceTree.Source));
#endif

            //proj.RemoveFile(proj.FindFileGuidByProjectPath("Libraries/Plugins/iOS/LGUnityiOSPlugin/LGCAppController.mm"));
            //proj.AddFileToBuildWithFlags(target,
            //                              proj.AddFile("Libraries/Plugins/iOS/LGUnityiOSPlugin/LGCAppController.mm",
            //                                            "Libraries/Plugins/iOS/LGUnityiOSPlugin/LGCAppController.mm",
            //                                            PBXSourceTree.Source),
            //                              "-fno-objc-arc");

            //proj.RemoveFile(proj.FindFileGuidByProjectPath("Libraries/Plugins/iOS/UnitySysFont.mm"));
            //proj.AddFileToBuildWithFlags(target,
                                          //proj.AddFile("Libraries/Plugins/iOS/UnitySysFont.mm",
                                          //              "Libraries/Plugins/iOS/UnitySysFont.mm",
                                          //              PBXSourceTree.Source),
                                          //"-fno-objc-arc");



            // 書き出し
            File.WriteAllText(projectPath, proj.WriteToString());

            // Info.plist
            UnityEngine.Debug.Log(">>>>>>>>>>>> game Updating Info.plist...");
            UpdateInfoPlist(path);

            //#endif

            var capManager = new ProjectCapabilityManager(projectPath, "XXXXX.entitlements", PBXProject.GetUnityTargetName());//创建设置Capability类
            capManager.AddPushNotifications(true);//设置Capability
            //capManager.AddGameCenter();
            capManager.AddInAppPurchase();
            capManager.WriteToFile();//写入文件保存


            //3、修改代码
            //读取UnityAppController.mm文件
            UnityEditor.XCodeEditor.XClass UnityAppController = new UnityEditor.XCodeEditor.XClass(path + "/Classes/UnityAppController.mm");
            //在指定代码后面增加一行代码
            UnityAppController.WriteBelow("#include \"PluginBase/AppDelegateListener.h\"", "\n#import \"GeTuiSdk.h\"");
            //个推获取device token
            string adInitCds = "  // [ GTSdk ]:向个推服务器注册deviceToken \n  NSString *token = [[deviceToken description] stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@\"<>\"]];\n token = [token stringByReplacingOccurrencesOfString: @\" \" withString: @\"\"]; \n [GeTuiSdk registerDeviceToken:token];";
            UnityAppController.WriteBelow("UnitySendDeviceToken(deviceToken);\n", adInitCds);
            //读取UnityAppController.mm文件
            UnityEditor.XCodeEditor.XClass Preprocessor = new UnityEditor.XCodeEditor.XClass(path + "/Classes/Preprocessor.h");
            Preprocessor.Replace("#define UNITY_USES_REMOTE_NOTIFICATIONS 0","#define UNITY_USES_REMOTE_NOTIFICATIONS 1");


        }
    }



    internal static void UpdateInfoPlist(string path) {
        var plist = PlistBuddyHelper.ForPlistFile(Path.Combine(path, "Info.plist"));
        // Bundle Identifier
        //plist.SetString("CFBundleIdentifier", PlayerSettings.applicationIdentifier);
        plist.SetBool("CFBundleAllowMixedLocalizations", true);
        plist.SetString("CFBundleDevelopmentRegion", "zh_CN");
        plist.SetString("CFBundleName", "XXXXXXX");
        plist.AddBool("NSAppTransportSecurity:NSAllowsArbitraryLoads", true);

        plist.AddString("NSPhotoLibraryUsageDescription", "需要您的同意,才能访问相册");//
        plist.AddString("NSMicrophoneUsageDescription", "需要您的同意,才能访问麦克风");
        plist.AddString("NSCameraUsageDescription", "需要您的同意,才能访问相机");
        plist.AddString("NSLocationWhenInUseUsageDescription","需要您的同意,才能访问位置");

        plist.AddBool("ITSAppUsesNonExemptEncryption",false);
        //LSApplicationQueriesSchemes
        //plist.AddArray("LSApplicationQueriesSchemes");
        //plist.AddString("LSApplicationQueriesSchemes:0", "mqq");//
        //plist.AddString("LSApplicationQueriesSchemes:1", "mqqapi");//
        //plist.AddString("LSApplicationQueriesSchemes:2", "mqqwpa");//
        //plist.AddString("LSApplicationQueriesSchemes:3", "mqqbrowser");
        //plist.AddString("LSApplicationQueriesSchemes:4", "mttbrowser");
        //plist.AddString("LSApplicationQueriesSchemes:5", "mqqOpensdkSSoLogin");
        //plist.AddString("LSApplicationQueriesSchemes:6", "mqqopensdkapiV2");
        //plist.AddString("LSApplicationQueriesSchemes:7", "sinaweibo");
        //plist.AddString("LSApplicationQueriesSchemes:8", "sinaweibohd");
        //plist.AddString("LSApplicationQueriesSchemes:9", "weibosdk");
        //plist.AddString("LSApplicationQueriesSchemes:10", "weibosdk2.5");
        //plist.AddString("LSApplicationQueriesSchemes:11", "weixin");

        //plist.AddString("LSApplicationQueriesSchemes:12", "wtloginmqq2");
        //plist.AddString("LSApplicationQueriesSchemes:13", "mqqapiwallet");
        //plist.AddString("LSApplicationQueriesSchemes:14", "mqqopensdkapiV3");
        //plist.AddString("LSApplicationQueriesSchemes:15", "mqqapiwallet");
        //plist.AddString("LSApplicationQueriesSchemes:16", "wechat");

        //UIBackgroundModes
        plist.AddArray("UIBackgroundModes");
        plist.AddString("UIBackgroundModes:0", "remote-notification");
        plist.AddString("UIBackgroundModes:1","voip");
        plist.AddBool("UIPushNotifications", true);


        ////weixin
        //plist.AddDictionary("CFBundleURLTypes", "1");
        //plist.AddString("CFBundleURLTypes:1:CFBundleTypeRole", "Editor");
        //plist.AddArray("CFBundleURLTypes", "1", "CFBundleURLSchemes");
        //plist.AddString("CFBundleURLTypes:1:CFBundleURLSchemes:0", "wx3ff69cc81203b2e1");

        ////tencent
        //plist.AddDictionary("CFBundleURLTypes", "2");
        //plist.AddString("CFBundleURLTypes:2:CFBundleTypeRole", "Editor");
        //plist.AddString("CFBundleURLTypes:2:CFBundleURLName", "tencentopenapi");
        //plist.AddArray("CFBundleURLTypes", "2", "CFBundleURLSchemes");
        //plist.AddString("CFBundleURLTypes:2:CFBundleURLSchemes:0", "tencent1106067576");

        ////weibo
        //plist.AddDictionary("CFBundleURLTypes", "3");
        //plist.AddString("CFBundleURLTypes:3:CFBundleTypeRole", "Editor");
        //plist.AddString("CFBundleURLTypes:3:CFBundleURLName", "com.weibo");
        //plist.AddArray("CFBundleURLTypes", "3", "CFBundleURLSchemes");
        //plist.AddString("CFBundleURLTypes:3:CFBundleURLSchemes:0", "wb2888694102");


        UnityEngine.Debug.Log(">>>>>>>>>>>>> Game Update Info Plist end");
    }

    internal static void AddDirectoryToXcodeproj(PBXProject proj, string targetGuid, string projectPath, string path, bool addSubDir = true) {
        UnityEngine.Debug.Log(">>>>> Game Adding to xcodeproj projectPath: " + projectPath + " path :" + path);
        string fullPath = Path.Combine(projectPath, path);
        UnityEngine.Debug.Log("fullPath:" + fullPath);
        if (Directory.Exists(fullPath)) {
            foreach (var file in Directory.GetFiles(fullPath)) {
                if (file.EndsWith(".meta")) continue;

                string filePath = Path.Combine(path, Path.GetFileName(file));
                UnityEngine.Debug.Log(">>>>> Game Adding to xcodeproj: " + filePath);
                proj.AddFileToBuild(targetGuid, proj.AddFile(filePath, filePath, PBXSourceTree.Source));
            }
            if (!addSubDir) {
                return;
            }
            foreach (var dir in Directory.GetDirectories(fullPath)) {
                string dirPath = Path.Combine(path, Path.GetFileName(dir));
                UnityEngine.Debug.Log(">>>> Game Adding dirPath to xcodeproj: " + dirPath);
                proj.AddFileToBuild(targetGuid, proj.AddFile(dirPath, dirPath, PBXSourceTree.Source));
            }
        } else {
            UnityEngine.Debug.LogWarning(">>>>Directory doesn't exist: " + fullPath);
        }
    }

    internal static void CopyDirectory(string srcPath, string dstPath) {
        using (var process = new Process()) {
            process.StartInfo.FileName = "/bin/cp";
            process.StartInfo.Arguments = string.Format("-Rf \"{0}\" \"{1}\"", srcPath, dstPath);
            UnityEngine.Debug.Log("Executing cp command: " + process.StartInfo.Arguments);

            process.StartInfo.CreateNoWindow = true;
            process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
            process.StartInfo.UseShellExecute = false;
            process.StartInfo.RedirectStandardError = true;
            process.StartInfo.RedirectStandardOutput = true;

            try {
                process.Start();
                process.StandardError.ReadToEnd();
                var stdError = process.StandardError.ReadToEnd();

                if (stdError.Trim().Length > 0) {
                    UnityEngine.Debug.Log("cp stderr: " + stdError);
                }

                if (!process.WaitForExit(10 * 1000)) {
                    throw new Exception("cp did not exit in a timely fashion");
                }

                if (process.ExitCode != 0) {
                    return;
                }

                return;
            } catch (Exception e) {
                throw new Exception("Encountered unexpected error while cp files.", e);
            }
        }
    }

    internal static void MoveItem(string srcPath, string dstPath) {
        using (var process = new Process()) {
            process.StartInfo.FileName = "/bin/mv";
            process.StartInfo.Arguments = string.Format("\"{0}\" \"{1}\"", srcPath, dstPath);
            UnityEngine.Debug.Log("Executing mv command: " + process.StartInfo.Arguments);

            process.StartInfo.CreateNoWindow = true;
            process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
            process.StartInfo.UseShellExecute = false;
            process.StartInfo.RedirectStandardError = true;
            process.StartInfo.RedirectStandardOutput = true;

            try {
                process.Start();
                process.StandardError.ReadToEnd();
                var stdError = process.StandardError.ReadToEnd();

                if (stdError.Trim().Length > 0) {
                    UnityEngine.Debug.Log("mv stderr: " + stdError);
                }

                if (!process.WaitForExit(10 * 1000)) {
                    throw new Exception("mv did not exit in a timely fashion");
                }

                if (process.ExitCode != 0) {
                    return;
                }

                return;
            } catch (Exception e) {
                throw new Exception("Encountered unexpected error while cp files.", e);
            }
        }
    }
}

#endif

你可能感兴趣的:(Unity3D,工具合集)