34

Unity3D研究院之IOS全自动编辑framework、plist、oc代码(六十七)

 3 years ago
source link: https://www.xuanyusong.com/archives/2720
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
首页 > Unity3D频道 > 【Unity3D研究院之游戏开发】 > Unity3D研究院之IOS全自动编辑framework、plist、oc代码(六十七)

Unity3D研究院之IOS全自动编辑framework、plist、oc代码(六十七)

Unity打IOS时会先生成一个Xcode工程,如果你需要增加一些第三方的framework那么需要手动一条一条的添加,这太烦了。。而且可能你还需要修改Plist文件,甚至还可能要修改unity自动生成的oc代码,每次打包都要修改的话,那太累了。。这篇文章就是全自动打包的第一步。。建议使用XUPorter,我在它的基础上拓展了两个类,一个用来修改plist,一个用来修改unity生成出来的OC代码。文章的最后我会给出代码。。

那么我用一个比较变态的SDK举个例子ShareSDK,它就需要自动添加framework,修改plist,还有要修改oc的代码。第一步打开XUPorter/Mods/share.projmods 文件。

    "group": "share",
    "libs": ["libicucore.dylib","libz.1.2.5.dylib"],
    "frameworks": [
                    "SystemConfiguration.framework",
     "QuartzCore.framework",
     "CoreTelephony.framework",
     "Security.framework",
                    "AdSupport.framework:optional",
                    "MessageUI.framework",
                     "StoreKit.framework",
                     "AudioToolbox.framework",
                     "QuartzCore.framework"
    "headerpaths": [],
    "files":   [
                "ShareSDK/Connection/SinaWeiboConnection.framework",
                "ShareSDK/Connection/WeChatConnection.framework",
                "ShareSDK/Core/AGCommon.framework",
                "ShareSDK/Core/ShareSDKCoreService.framework",
                "ShareSDK/ShareSDK.framework"
    "folders": ["ShareSDK/"],    
    "excludes": ["^.*.meta$", "^.*.mdown$", "^.*.pdf$"],
    "linker_flags": []

 frameworks分成两种,一种是系统自带的framework还有一种是第三方的framework。 “frameworks”节点里面放的是系统自带的frameworks。”files”节点里面放的是第三方做出来的framework。 尤其是第三方的framework如果位置放的不对,就不会被xcode所引用的!切记切记!!

folders:可以把某个文件夹下的所有文件拷贝在xcode工程里面,一般sdk都会附带一些oc的代码文件,最好通过folders把oc的代码拷贝在工程里面。或者你也可以把oc的代码放在plugins下面,同样打包的时候也会拷贝进xcode工程。

unity打完IOS或者Android包以后会自动回调一个静态方法。

    [PostProcessBuild (100)]
    public static void OnPostProcessBuild (BuildTarget target, string pathToBuiltProject)

 自动添加framework的原理其实就是等包打完以后,在这个方法里面进行文件的操作,把需要的framework plist oc 代码拷贝进去,或者修改它们。。

using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
using UnityEditor.Callbacks;
using UnityEditor.XCodeEditor;
using System.Xml;
#endif
using System.IO;
public static class XCodePostProcess
    #if UNITY_EDITOR
    [PostProcessBuild (100)]
    public static void OnPostProcessBuild (BuildTarget target, string pathToBuiltProject)
        if (target != BuildTarget.iPhone) {
            Debug.LogWarning ("Target is not iPhone. XCodePostProcess will not run");
            return;
        //得到xcode工程的路径
        string path = Path.GetFullPath (pathToBuiltProject);
        // Create a new project object from build target
        XCProject project = new XCProject (pathToBuiltProject);
        // Find and run through all projmods files to patch the project.
        // Please pay attention that ALL projmods files in your project folder will be excuted!
        //在这里面把frameworks添加在你的xcode工程里面
        string[] files = Directory.GetFiles (Application.dataPath, "*.projmods", SearchOption.AllDirectories);
        foreach (string file in files) {
            project.ApplyMod (file);
        //增加一个编译标记。。没有的话sharesdk会报错。。
        project.AddOtherLinkerFlags("-licucore");
        //设置签名的证书, 第二个参数 你可以设置成你的证书
project.overwriteBuildSetting ("CODE_SIGN_IDENTITY", "xxxxxx", "Release");
        project.overwriteBuildSetting ("CODE_SIGN_IDENTITY", "xxxxxx", "Debug");
        // 编辑plist 文件
        EditorPlist(path);
        //编辑代码文件
        EditorCode(path);
        // Finally save the xcode project
        project.Save ();
    private static void EditorPlist(string filePath)
        XCPlist list =new XCPlist(filePath);
        string bundle = "com.yusong.momo";
        string PlistAdd = @"  
            <key>CFBundleURLTypes</key>
            <array>
            <dict>
            <key>CFBundleTypeRole</key>
            <string>Editor</string>
            <key>CFBundleURLIconFile</key>
            <string>Icon@2x</string>
            <key>CFBundleURLName</key>
            <string>"+bundle+@"</string>
            <key>CFBundleURLSchemes</key>
            <array>
            <string>ww123456</string>
            </array>
            </dict>
            </array>";
        //在plist里面增加一行
        list.AddKey(PlistAdd);
        //在plist里面替换一行
        list.ReplaceKey("<string>com.yusong.${PRODUCT_NAME}</string>","<string>"+bundle+"</string>");
        list.Save();
    private static void EditorCode(string filePath)
//读取UnityAppController.mm文件
        XClass UnityAppController = new XClass(filePath + "/Classes/UnityAppController.mm");
        //在指定代码后面增加一行代码
        UnityAppController.WriteBelow("#include \"PluginBase/AppDelegateListener.h\"","#import <ShareSDK/ShareSDK.h>");
        //在指定代码中替换一行
        UnityAppController.Replace("return YES;","return [ShareSDK handleOpenURL:url sourceApplication:sourceApplication annotation:annotation wxDelegate:nil];");
        //在指定代码后面增加一行
        UnityAppController.WriteBelow("UnityCleanup();\n}","- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url\r{\r    return [ShareSDK handleOpenURL:url wxDelegate:nil];\r}");
    #endif

在回到ShareSDK上,在接微信平台的时候,它们需要在pList 里面增加URL types选项,这里我通过XCPlist增加一行 或者替换一行。

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.IO;
namespace UnityEditor.XCodeEditor
    public partial class XCPlist : System.IDisposable
private string filePath;
List<string> contents = new List<string>();
public XCPlist(string fPath)
            filePath = Path.Combine( fPath, "info.plist" );
            if( !System.IO.File.Exists( filePath ) ) {
                Debug.LogError( filePath +"路径下文件不存在" );
    return;
            FileInfo projectFileInfo = new FileInfo( filePath );
StreamReader sr = projectFileInfo.OpenText();
while (sr.Peek() >= 0)
contents.Add(sr.ReadLine());
sr.Close();
public void AddKey(string key)
if(contents.Count < 2)
return;
contents.Insert(contents.Count - 2,key);
public void ReplaceKey(string key,string replace){
for(int i = 0;i < contents.Count;i++){
if(contents[i].IndexOf(key) != -1){
contents[i] = contents[i].Replace(key,replace);
public void Save()
            StreamWriter saveFile = File.CreateText(filePath);
foreach(string line in contents)
saveFile.WriteLine(line);
saveFile.Close();
public void Dispose()

 ShareSDK在接入微信平台的时候 必须修改Unity生成的UnityAppController.mm 文件,这里我通过 XClass 自动修改UnityAppController.mm生成的代码。 主要是增加代码和替换代码 两部分。。

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.IO;
namespace UnityEditor.XCodeEditor
public partial class XClass : System.IDisposable
        private string filePath;
public XClass(string fPath)
            filePath = fPath;
if( !System.IO.File.Exists( filePath ) ) {
Debug.LogError( filePath +"路径下文件不存在" );
return;
        public void WriteBelow(string below, string text)
            StreamReader streamReader = new StreamReader(filePath);
            string text_all = streamReader.ReadToEnd();
            streamReader.Close();
            int beginIndex = text_all.IndexOf(below);
            if(beginIndex == -1){
                Debug.LogError(filePath +"中没有找到标致"+below);
                return;
            int endIndex = text_all.LastIndexOf("\n", beginIndex + below.Length);
            text_all = text_all.Substring(0, endIndex) + "\n"+text+"\n" + text_all.Substring(endIndex);
            StreamWriter streamWriter = new StreamWriter(filePath);
            streamWriter.Write(text_all);
            streamWriter.Close();
        public void Replace(string below, string newText)
            StreamReader streamReader = new StreamReader(filePath);
            string text_all = streamReader.ReadToEnd();
            streamReader.Close();
            int beginIndex = text_all.IndexOf(below);
            if(beginIndex == -1){
                Debug.LogError(filePath +"中没有找到标致"+below);
                return;
            text_all =  text_all.Replace(below,newText);
            StreamWriter streamWriter = new StreamWriter(filePath);
            streamWriter.Write(text_all);
            streamWriter.Close();
        public void Dispose()

像这样,我就可以把unity生成的代码修改了。。

Unity3D研究院之IOS全自动编辑framework、plist、oc代码(六十七) - 雨松MOMO程序研究院 - 1

最后是工程地址:http://pan.baidu.com/s/1i3gLDTN

建议大家把工程下载下来看看一基本上就明白它的工作原理了。如果你掌握者本篇文章的知识 那么恭喜你 自动化打包就已经完成了一半。。 现在我们已经可以自动化生成 xcode工程了,等有时间的话我会把下一半shell 自动化打包.ipa的方法在整理出来。。

作者:雨松MOMO
专注移动互联网,Unity3D游戏开发
捐 赠写博客不易,如果您想请我喝一杯星巴克的话?就进来看吧!

Unity3D研究院之IOS全自动编辑framework、plist、oc代码(六十七)》有 61 条评论

  1. 273c08b9fc10543dccbbaf75b76115b8?s=80zw 说:

    你好,这个帖子比较早了。想问下,这个方法现在还适用吗

  2. 4efabfbf34b1664ce9710be75cc94ce4?s=80姚子东 说:

    momo大神,我想问下,为什么要在打包完成之后,对framework和oc代码进行设置?不应该是在打包之前进行的设置吗??

    • ?s=80哈哈哈哈 说:

      雨松大大,还有一个问题求解。StoaryBoard文件如何添加到xcode工程里,我之前把它从unity里复制到xcode工程里,但是Copy Bundle Resource里边没有链接到,导致程序因为找不到StoaryBoard直接crash。

  3. ?s=80john 说:

    如果只是在自己手机上安装ipa,还需要开发者账号吗?

  4. ?s=80王闯 说:

    momo大神问个问题 ,projmod文件的 “compiler_flags”这个标签改怎么用啊,我现在用到了第三方的开源库 AFWorking 需要在配置compile flags的参数为 -fobjc -arc。我试了”compiler_flags”:[“-fobjc -arc”]这个写好像不对。

  5. ?s=80无忧小子 说:

    momo大神,讲的非常好。[奥特曼]
    顺便请教下 如果unity编译Xcode项目的时候,需要添加Associated Domains 得值,可以通过这个插件实现吗?

  6. ?s=80晴天猪 说:

    这个可以把库 加入到 Embedded Binaries 中嘛?[可怜]

  7. ?s=80王湃 说:

    想请问一下 添加的文件怎么能加到copy bundle resources里面啊?

  8. ?s=80venbb 说:

    怎么自动添加AppIcon啊?

  9. ?s=80Jing 说:

    我这边需要加入ios钥匙链,其中苹果给的范例代码需要给单独文件加编译选项“-fno-objc-arc”,这个有什么办法吗

  10. ?s=80AK 说:

    兄弟,我的libs下的导入也是红色的字体,后面你是怎么导入的呢?

  11. ?s=80AK 说:

    libs目录下的不能自动添加,求指点

  12. ?s=80gangge 说:

    雨松大大,我想问下,Xcode 生成完成得时候 总是会显示 DXTPlugInCompatibilityUUIDs的报错 ,这个是什么原因?有什么解决的例子吗?

  13. ?s=80TrustTJM 说:

    请问一下雨松大大,我查了许久XUPorter,都是比较老的,针对现在的Xcode6和Unity5还好使吗

  14. ?s=80夏染七日 说:

    我们用了unilua ,不过mono内存一直降不下来,可能我们用的姿势不对,后来用C#重构了。蛋疼。

  15. ?s=80爱好者 说:

    很郁闷!加一个广告的sdk,在bundle文件中有个js脚本,到unity里面就开始报这个js脚本错误

    • ?s=80jehovah0121 说:

      可以考虑集成到 Unity 的时候改名,导出到 Xcode 中之后再改回来。或者放在 Unity 之外的文件夹中,到 Xcode 中用脚本将它加进去。

  16. 为何修改share.projmods 就会报错 UnityException: Parse error in file share.projmods! Check for typos such as unbalanced quotation marks, etc.

    • 后来解决了,解决方案是用windows电脑去改这个配置表然后传给mac电脑使用就不会出错了。继续关注这个问题,看看还有更好的解决方案不。

  17. ?s=80MONO粉 说:

    xcode更新6.1之后,这个方法不行了…… Unity3D研究院之IOS全自动编辑framework、plist、oc代码(六十七) - 雨松MOMO程序研究院 - 1

  18. hi momo师兄,关于修改UnityAppController.mm 的方法,我想到另一个解决方案,就是派生一个UnityAppController的子类CustomUnityAppController,将然后将涉及到 对UnityAppController的修改都在CustomUnityAppController中实现,并将main.mm中的”const char* AppControllerClassName = “UnityAppController”;” 修改为”const char* AppControllerClassName = “CustomUnityAppController”;” 这样做代码维护性要高一些。

  19. ?s=80Eric 说:

    同样遇到了添加系统自带的framework是红色字体,添加失败

  20. ?s=80xlym 说:

    大神 问下哈~~我在https://github.com/onevcat/XUPorter 下的插件,但是folders中的文件add不进xcode,但是用你的demo可以,请问你在里面做更改了嘛=。=

  21. ?s=80李浩 说:

    MOMO大神问个问题哈,”folders”: [“ShareSDK/”], 这样写就可以把这个文件夹下的所有东西拷贝到Xcode工程里了?这个ShareSDK的文件夹我看您的demo里放在XUPorterMods路径下了,我也把要加的文件夹放在了这个路径下,projmods 文件中我也写了这个文件夹名,但是打包出的Xcode工程中并没加进去这些东西啊,这是什么问题呢

  22. ?s=80黑金 说:

    MOMO大神请教一下,在接某sdk时 它需要将assets文件夹拖入xcode工程的SDK目录下并选择Create folder references for any added folders.之后就变成蓝色文件夹了。但在xcode工程之前拖入好进入到打开工程再编译好运行就不行,MOMO遇到过这样的SDK吗?如果不能用命令行或代码实现,就不能自动化了。。。%>_<%

  23. ?s=80黑金 说:

    XCMod.cs中_libs初始化为null就可以了,下文的getter判断的是null不是size

  24. 04e8becbc3190ca3364a5a54fd5c38b0?s=80Peter 说:

    确实 libs里添加动态库,导入XCODE后仍然没有添加动态库文件,不知道什么原因

  25. ?s=80赵雪飞 说:

    xuporter能在windows下的unity使用吗

  26. 哦,那么例如我想添加libz.dylib,那么我只需要将这个libz.dylib添加到share.projmods的lib里就可以了吗? 但我这样添加我并没有在导出的工程里面看到加载进来的这个dylib,当我将libz.dylib放到share.projmods的framework中后,导出的xcode工程是能在framework中看到libz.dylib的,但是framework列表里面libz.dylib是红色字体显示的,这是代表没有正常导入吗?

  27. 大mo神,你好,我下载了你的demo,发现没有起效果,在demo中,project.overwriteBuildSetting (“CODE_SIGN_IDENTITY”, “xxxxxx”, “Release”);这个签名证书指的是什么呢?

  28. 814ccdfff321f4a630230c2f9e970e5f?s=80小鱼 说:

    momo大神什么时候写点资源更新这一块啊?

留下一个回复 取消回复

你的email不会被公开。

评论

姓名 *

电子邮件 *

站点


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK