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生成的代码修改了。。
最后是工程地址:http://pan.baidu.com/s/1i3gLDTN
建议大家把工程下载下来看看一基本上就明白它的工作原理了。如果你掌握者本篇文章的知识 那么恭喜你 自动化打包就已经完成了一半。。 现在我们已经可以自动化生成 xcode工程了,等有时间的话我会把下一半shell 自动化打包.ipa的方法在整理出来。。
- 本文固定链接: https://www.xuanyusong.com/archives/2720
- 转载请注明: 雨松MOMO于 雨松MOMO程序研究院 发表


libs目录下的不能自动添加,求指点
雨松大大,我想问下,Xcode 生成完成得时候 总是会显示 DXTPlugInCompatibilityUUIDs的报错 ,这个是什么原因?有什么解决的例子吗?
Xcode 升级后, Unity 就无法自动启动Xcode…可参考该博文处理 http://www.cnblogs.com/TracePlus/p/4047628.html
请问一下雨松大大,我查了许久XUPorter,都是比较老的,针对现在的Xcode6和Unity5还好使吗
好使啊。。 这就是 本文的读写操作。。。
你在Unity5.0里怎么用的?
就原来这样用咧,没区别的
恩,是的。多谢[嘻嘻]
我们用了unilua ,不过mono内存一直降不下来,可能我们用的姿势不对,后来用C#重构了。蛋疼。
很郁闷!加一个广告的sdk,在bundle文件中有个js脚本,到unity里面就开始报这个js脚本错误
可以考虑集成到 Unity 的时候改名,导出到 Xcode 中之后再改回来。或者放在 Unity 之外的文件夹中,到 Xcode 中用脚本将它加进去。
为何修改share.projmods 就会报错 UnityException: Parse error in file share.projmods! Check for typos such as unbalanced quotation marks, etc.
后来解决了,解决方案是用windows电脑去改这个配置表然后传给mac电脑使用就不会出错了。继续关注这个问题,看看还有更好的解决方案不。
多谢,好文!!!!
xcode更新6.1之后,这个方法不行了……
真的假的?
hi momo师兄,关于修改UnityAppController.mm 的方法,我想到另一个解决方案,就是派生一个UnityAppController的子类CustomUnityAppController,将然后将涉及到 对UnityAppController的修改都在CustomUnityAppController中实现,并将main.mm中的”const char* AppControllerClassName = “UnityAppController”;” 修改为”const char* AppControllerClassName = “CustomUnityAppController”;” 这样做代码维护性要高一些。
嗯是的。 一般向和oc交互比较频繁的 这样做再好不过的。。 一般没什么交互的,就自动生成一下就好。。
同样遇到了添加系统自带的framework是红色字体,添加失败
大神 问下哈~~我在https://github.com/onevcat/XUPorter 下的插件,但是folders中的文件add不进xcode,但是用你的demo可以,请问你在里面做更改了嘛=。=
MOMO大神问个问题哈,”folders”: [“ShareSDK/”], 这样写就可以把这个文件夹下的所有东西拷贝到Xcode工程里了?这个ShareSDK的文件夹我看您的demo里放在XUPorterMods路径下了,我也把要加的文件夹放在了这个路径下,projmods 文件中我也写了这个文件夹名,但是打包出的Xcode工程中并没加进去这些东西啊,这是什么问题呢
MOMO大神请教一下,在接某sdk时 它需要将assets文件夹拖入xcode工程的SDK目录下并选择Create folder references for any added folders.之后就变成蓝色文件夹了。但在xcode工程之前拖入好进入到打开工程再编译好运行就不行,MOMO遇到过这样的SDK吗?如果不能用命令行或代码实现,就不能自动化了。。。%>_<%
XCMod.cs中_libs初始化为null就可以了,下文的getter判断的是null不是size
谢谢!!!
确实 libs里添加动态库,导入XCODE后仍然没有添加动态库文件,不知道什么原因
xuporter能在windows下的unity使用吗
哦,那么例如我想添加libz.dylib,那么我只需要将这个libz.dylib添加到share.projmods的lib里就可以了吗? 但我这样添加我并没有在导出的工程里面看到加载进来的这个dylib,当我将libz.dylib放到share.projmods的framework中后,导出的xcode工程是能在framework中看到libz.dylib的,但是framework列表里面libz.dylib是红色字体显示的,这是代表没有正常导入吗?
大mo神,你好,我下载了你的demo,发现没有起效果,在demo中,project.overwriteBuildSetting (“CODE_SIGN_IDENTITY”, “xxxxxx”, “Release”);这个签名证书指的是什么呢?
momo大神什么时候写点资源更新这一块啊?
不明觉厉!