首页 >Unity3D频道 >【Unity3D研究院之游戏开发】 > Unity3D研究院之IOS全自动编辑framework、plist、oc代码(六十七)
2014
06-09

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 *)urlr{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生成的代码修改了。。

屏幕快照 2014-06-09 下午10.56.56

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

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

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

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

  1. zw说:

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

  2. 姚子东说:

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

  3. 王景伟说:

    松哥,tbd文件怎么添加啊??

  4. plist就是个文本。 用File类就能操作它

    • 哈哈哈哈说:

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

  5. john说:

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

  6. 王闯说:

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

  7. 无忧小子说:

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

  8. 晴天猪说:

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

  9. 王湃说:

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

  10. 杜三狗说:

    plist文件在xcode工程中打不开了怎么回事啊。the data couldn’t be read because it isn’t the correct format提示这个错格式不对了。

  11. venbb说:

    怎么自动添加AppIcon啊?

  12. Jing说:

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

  13. AK说:

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

留下一个回复

你的email不会被公开。 必填项已用 * 标注。