功能:
使用Unity 5.x自带API打包Xcode工程自动添加framework、plist、lib、和插入OC代码参考文章:
http://www.xuanyusong.com/archives/4026
http://www.xuanyusong.com/archives/2720
http://www.jianshu.com/p/f347e00abb9c
http://www.jianshu.com/p/dbd7c4b205b0官方API:
https://docs.unity3d.com/ScriptReference/iOS.Xcode.PBXProject.html
开发环境
OS:macOS Sierra 10.12.2
Unity:5.3.6(p8)
Xcode:8.2
特别注意
以下的代码文件必须放在Unity工程下的Editor文件夹内才能生效否则会报错!
PBXProjectDemo.cs
using System.IO;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
using UnityEditor.iOS.Xcode;
using UnityEditor.Callbacks;
using UnityEditor.XCodeEditor;
#endif
using System.Collections;
public class PBXProjectDemo
{
//该属性是在build完成后,被调用的callback
[PostProcessBuildAttribute(0)]
public static void OnPostprocessBuild(BuildTarget buildTarget, string pathToBuiltProject)
{
// BuildTarget需为iOS
if (buildTarget != BuildTarget.iOS)
return;
// 初始化
var projectPath = pathToBuiltProject + "/Unity-iPhone.xcodeproj/project.pbxproj";
PBXProject pbxProject = new PBXProject();
pbxProject.ReadFromFile(projectPath);
string targetGuid = pbxProject.TargetGuidByName("Unity-iPhone");
// 添加flag
pbxProject.AddBuildProperty(targetGuid, "OTHER_LDFLAGS", "-ObjC");
// 关闭Bitcode
pbxProject.SetBuildProperty(targetGuid, "ENABLE_BITCODE", "NO");
// 添加framwrok
pbxProject.AddFrameworkToProject(targetGuid, "Security.framework", false);
pbxProject.AddFrameworkToProject(targetGuid, "CoreTelephony.framework", false);
pbxProject.AddFrameworkToProject(targetGuid, "SystemConfiguration.framework", false);
pbxProject.AddFrameworkToProject(targetGuid, "CoreGraphics.framework", false);
pbxProject.AddFrameworkToProject(targetGuid, "ImageIO.framework", false);
pbxProject.AddFrameworkToProject(targetGuid, "CoreData.framework", false);
//添加lib
AddLibToProject(pbxProject, targetGuid, "libsqlite3.tbd");
AddLibToProject(pbxProject, targetGuid, "libc++.tbd");
AddLibToProject(pbxProject, targetGuid, "libz.tbd");
// 应用修改
File.WriteAllText(projectPath, pbxProject.WriteToString());
// 修改Info.plist文件
var plistPath = Path.Combine(pathToBuiltProject, "Info.plist");
var plist = new PlistDocument();
plist.ReadFromFile(plistPath);
// 插入URL Scheme到Info.plsit(理清结构)
var array = plist.root.CreateArray("CFBundleURLTypes");
//插入dict
var urlDict = array.AddDict();
urlDict.SetString("CFBundleTypeRole", "Editor");
//插入array
var urlInnerArray = urlDict.CreateArray("CFBundleURLSchemes");
urlInnerArray.AddString("blablabla");
// 应用修改
plist.WriteToFile(plistPath);
//插入代码
//读取UnityAppController.mm文件
string unityAppControllerPath = pathToBuiltProject + "/Classes/UnityAppController.mm";
XClass UnityAppController = new XClass(unityAppControllerPath);
//在指定代码后面增加一行代码
UnityAppController.WriteBelow("#include \"PluginBase/AppDelegateListener.h\"", "#import <UMSocialCore/UMSocialCore.h>");
string newCode = "\n" +
" [[UMSocialManager defaultManager] openLog:YES];\n" +
" [UMSocialGlobal shareInstance].type = @\"u3d\";\n" +
" [[UMSocialManager defaultManager] setUmSocialAppkey:@\"" +"\"];\n" +
" [[UMSocialManager defaultManager] setPlaform:UMSocialPlatformType_WechatSession appKey:@\""+"\" appSecret:@\""+ "\" redirectURL:@\"http://mobile.umeng.com/social\"];\n" +
" \n"
;
//在指定代码后面增加一大行代码
UnityAppController.WriteBelow("// if you wont use keyboard you may comment it out at save some memory", newCode);
}
//添加lib方法
static void AddLibToProject(PBXProject inst, string targetGuid, string lib)
{
string fileGuid = inst.AddFile("usr/lib/" + lib, "Frameworks/" + lib, PBXSourceTree.Sdk);
inst.AddFileToBuild(targetGuid, fileGuid);
}
}
XClass.cs
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()
{
}
}
}
XCPlist.cs
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()
{
}
}
}