目录

1. 代码仓库

2. 代码展示

3. Feature 2017.3.29 设置Xcode Capabilities

4. Add Localizations 2017-04-07

5. 构建API

6. XUPorter 不建议使用

7. 新问题-2017.10.27


0.最近更新

添加微信SDK导出,修改xcode工程 添加plist scheme。

 

1.代码仓库


下载地址: https://bitbucket.org/Unity-Technologies/xcodeapi


2.代码展示

支持:Unity : 5.4.1p1+   /   Xcode: 8.1+

PostProcessBuild (在Unity编译的最后加入了一个脚本调用的命令,会自动搜索Editor文件夹下的PostprocessBuildPlayer,并进行调用)。

  • 主函数入口

public override void OnPostprocessBuild (BuildTarget BuildTarget, string path){
	if (BuildTarget == BuildTarget.iOS) {
		string projPath = PBXProject.GetPBXProjectPath (path);
		PBXProject proj = new PBXProject ();
		proj.ReadFromString (File.ReadAllText (projPath));

		generateProjFile (proj, path);//处理Xcode工程

		string plistPath = path + "/Info.plist";
		PlistDocument plist = new PlistDocument ();
		plist.ReadFromString (File.ReadAllText (plistPath));

		generatePlistFile (plist.root, path);//处理plist文件


		File.WriteAllText (projPath, proj.WriteToString ());
		File.WriteAllText (plistPath, plist.WriteToString ());

		this.ParseIcon ();
		/*
		this.ParseSplashXLib (new Color (34 / 255f, 44 / 255f, 55 / 255f));//修改背景色
		this.Buildipa();//代码请见Part2博客
		generateFBSettingsConfig();// FaceBook SDK
		generateHelpShiftConfig();//Helpshift SDK
		*/
	}
}
  • 处理Xcode工程配置

private void generateProjFile(PBXProject proj,string path){
	string target = proj.TargetGuidByName (PBXProject.GetUnityTargetName ());

	var codesign = Debug.isDebugBuild ? "iPhone Developer: xxxxxxxxxxx" : "iPhone Distribution: xxxxxxxx";
	var provision = Debug.isDebugBuild ? "xxxxx" : "xxxxx";

	proj.SetBuildProperty (target, "CODE_SIGN_IDENTITY", codesign);
	proj.SetBuildProperty (target, "PROVISIONING_PROFILE_SPECIFIER", provision);
	proj.SetBuildProperty (target, "CODE_SIGN_ENTITLEMENTS", "KeychainAccessGroups.plist");
	proj.SetBuildProperty (target, "DEVELOPMENT_TEAM", "xxxxxxxxxx");

	proj.SetBuildProperty (target, "ENABLE_BITCODE", "NO");
	proj.SetSystemCapabilities (target, "com.apple.Push", "1");
	proj.SetSystemCapabilities (target, "com.apple.GameCenter", "1");
	proj.SetSystemCapabilities (target, "com.apple.InAppPurchase", "1");
	proj.RemoveFilesByProjectPathRecursive ("Libraries/Plugins/Android"); // 移除某个目录,根据开发者需求

	proj.AddBuildProperty (target, "HEADER_SEARCH_PATHS", Application.dataPath + "/_PlatformAssets/Platforms/xxxxxxxx");//修改Xcode索引目录

	//keychain
	proj.AddFile (Application.dataPath + "你的目录/KeychainAccessGroups.plist", "KeychainAccessGroups.plist");
	proj.SetBuildProperty (target, "CODE_SIGN_ENTITLEMENTS", Application.dataPath + "你的目录/KeychainAccessGroups.plist");

    // weixin framework
	// proj.AddFrameworkToProject (target, "SystemConfiguration.framework", false);

	// SvUDIDTools是UDID文件,可以忽略。
	// AddFile添加文件到Xcode目录,返回文件GUID
	// AddFileToBuild功能是将GUID文件添加到Xcode BuildPhases阶段
	var fileGUID = "";
	fileGUID = proj.AddFile (Application.dataPath + "你的目录/SvUDIDTools.h", "Libraries/Plugins/IOS/SvUDIDTool/SvUDIDTools.h");
	proj.AddFileToBuild (target, fileGUID);
	fileGUID = proj.AddFile (Application.dataPath + "你的目录/SvUDIDTools.m", "Libraries/Plugins/IOS/SvUDIDTool/SvUDIDTools.m");
	proj.AddFileToBuild (target, fileGUID);//添加到Xcode BuildPhases阶段

	// localizable 自动添加Xcode语言文件
	var infoDirs = Directory.GetDirectories (Application.dataPath + "你的目录/lang/infoplist/");
	for (var i = 0; i < infoDirs.Length; ++i) {
		var files = Directory.GetFiles (infoDirs [i], "*.strings");
		proj.AddLocalization (files [0], "InfoPlist.strings", "InfoPlist.strings");
	}

	var localdirs = Directory.GetDirectories (Application.dataPath + "你的目录/lang/localizable/");
	for (var i = 0; i < localdirs.Length; ++i) {
		var files = Directory.GetFiles (localdirs [i], "*.strings");
		proj.AddLocalization (files [0], "Localizable.strings", "Localizable.strings");
	}
	fileGUID = proj.AddFile (Application.dataPath + "/Plugins/IOS/notificationsound.caf", "notificationsound.caf"); // 添加推送音效
	proj.AddFileToBuild (target, fileGUID);
}
  • 处理plist文件内容

private void generatePlistFile(PlistElementDict rootDict,string path){
	rootDict.SetString ("CFBundleIdentifier", "com.gekko.rok");
	rootDict.SetString ("CFBundleDisplayName", "Rage of Kings");
	rootDict.SetString ("CFBundleVersion", GetVer ());
	rootDict.SetString ("NSPhotoLibraryUsageDescription", "Use Photo");
	rootDict.SetString ("NSCameraUsageDescription", "Use Camera");
	rootDict.SetString ("CFBundleShortVersionString", GKVersion.GAME_VERSION);
	rootDict.SetString ("ITSAppUsesNonExemptEncryption", "false");
        rootDict.SetString ("LSHasLocalizedDisplayName","true");

	// weixin scheme
	PlistElementArray urlArray = null;
	if (!rootDict.values.ContainsKey ("CFBundleURLTypes")) {
		urlArray = rootDict.CreateArray ("CFBundleURLTypes");
	} else {
		urlArray = rootDict.values ["CFBundleURLTypes"].AsArray ();
	}
	var urlTypeDict = urlArray.AddDict();
	urlTypeDict.SetString("CFBundleURLName", "weixin");
	var urlScheme = urlTypeDict.CreateArray("CFBundleURLSchemes");
	urlScheme.AddString("weixin_id");

	if (!rootDict.values.ContainsKey ("LSApplicationQueriesSchemes")) {
		urlArray = rootDict.CreateArray ("LSApplicationQueriesSchemes");
	} else {
		urlArray = rootDict["LSApplicationQueriesSchemes"].AsArray();
	}
	urlArray.AddString ("weixin");

	// Gamecenter
	if (rootDict.values.ContainsKey ("UIRequiredDeviceCapabilities")) {
		rootDict.values.Remove ("UIRequiredDeviceCapabilities");
	}
	var arr = rootDict.CreateArray ("UIRequiredDeviceCapabilities");
	arr.AddString ("armv7");
	arr.AddString ("gamekit");
}
  • 处理Icon 

protected void ParseIcon(){
	string sourcePath = "/_ExportTextures/appIcon/{0}.png";
	var icoList = new List<string> () {
		"Icon",
		"Icon-72",
		"Icon-76",
		"Icon-120",
		"Icon@2x",
		"Icon-144",
		"Icon-152",
		"Icon-167",
		"Icon-180",
		"Icon-Store"//1024*1024 , xcode9+
	};
	foreach (var ico in icoList) {
		File.Copy (Application.dataPath + string.Format (sourcePath, ico), XCodeProjectMod.XcodePath() + string.Format ("/Unity-iPhone/Images.xcassets/AppIcon.appiconset/{0}.png", ico), true);
	}
}
  • 处理背景色

//using System.Xml;
protected void ParseSplashXLib(Color color){
	Action<string> ModifyXML = (xmlPath) => {
		XmlDocument xmlDoc = new XmlDocument ();
		xmlDoc.Load (xmlPath);
		XmlNodeList nodelist = xmlDoc.SelectSingleNode ("document").ChildNodes;
		foreach (XmlElement item in nodelist) {
			if (item.Name == "objects") {
				foreach (XmlElement item1 in item.ChildNodes) {
					if (item1.Name == "view") {
						foreach (XmlElement item2 in item1.ChildNodes) {
							if (item2.Name == "color") {
								item2.SetAttribute ("red", color.r.ToString ());
								item2.SetAttribute ("green", color.g.ToString ());
								item2.SetAttribute ("blue", color.b.ToString ());
								item2.SetAttribute ("alpha", color.a.ToString ());
							}
						}
					}
				}
			}
		}
		xmlDoc.Save (xmlPath);
	};

	ModifyXML (XCodeProjectMod.XcodePath () + "/LaunchScreen-iPhone.xib");
	ModifyXML (XCodeProjectMod.XcodePath () + "/LaunchScreen-iPad.xib");
}

 

3.Feature 2017.3.29 设置Xcode Capabilities

SetSystemCapabilities函数实现 //proj.SetSystemCapabilities (target, "com.apple.Push","1")

//PBXProjects.cs文件
public void SetSystemCapabilities(string target,string key,string value){
	project.project.SetSystemCapabilities (target, key, value);
}

//找到Objects.cs => internal class PBXProjectObjectData : PBXObjectData类内添加此函数
public void SetSystemCapabilities(string target,string key,string value){
	if (m_Properties.Contains ("attributes")) {
		var attributes = m_Properties ["attributes"].AsDict ();
		var targetAttributes = attributes ["TargetAttributes"].AsDict ();
		if (targetAttributes.Contains (target)) {
			var targetDict = targetAttributes [target].AsDict ();
			if (!targetDict.Contains ("SystemCapabilities")) {
				var dict = targetDict.CreateDict ("SystemCapabilities");
				var record = dict.CreateDict (key);
				record.SetString ("enabled", value);
			} else {
				var dict = targetDict ["SystemCapabilities"].AsDict ();
				if (!dict.Contains (key)) {
					var record = dict.CreateDict (key);
					record.SetString ("enabled", value);
				} else {
					var record = dict [key].AsDict ();
					record.SetString ("enabled", value);
				}
			}
		} else {
			//error
		}
	}
}

4.Add Localizations 2017-04-07

添加本地化文件此功能没有进入到stable分支, 而是在pull requests内  。
https://bitbucket.org/Unity-Technologies/xcodeapi/pull-requests/13/creation-of-variantgroup-and/diff

代码需要自己移植到项目内,语言文件需要自己首先在Xcode工程里创建好,然后拷贝到Unity Assets内。

我的Unity文件目录:

示例代码:

var infoDirs = Directory.GetDirectories (Application.dataPath + "/IOS/lang/infoplist/");
for (var i = 0; i < infoDirs.Length; ++i) {
    var files = Directory.GetFiles (infoDirs [i], "*.strings");
    proj.AddLocalization (files [0], "InfoPlist.strings", "InfoPlists.strings");
}
 
var localdirs = Directory.GetDirectories (Application.dataPath + "/IOS/lang/localizable/");
for (var i = 0; i < localdirs.Length; ++i) {
    var files = Directory.GetFiles (localdirs [i], "*.strings");
    proj.AddLocalization (files [0], "Localizable.strings", "Localizable.strings");
}


最终会在Xcode工程内出现下图内容:

5.构建API

case Configuration.Debug:
    BuildPipeline.BuildPlayer (GetBuildScenes(),XcodePath(),BuildTarget.iOS,BuildOptions.AllowDebugging | BuildOptions.SymlinkLibraries | BuildOptions.Development);
break;
case Configuration.Release:
    BuildPipeline.BuildPlayer (GetBuildScenes(),XcodePath(),BuildTarget.iOS,BuildOptions.None);
break;

  *上面贴的代码是调用unity build命令,开始build。

  *可以添加Menu Item 功能菜单,点击Item按钮调用代码,自动打包构建Xcode工程,上传bugly,发邮件通知(都已实现)

6.XUPorter 不建议使用

之前用的是这款开源工具,现该项目作者已不维护,Unity5.x 之后版本更换方式。

7. 新问题-2017.10.27

新版本的Unity 2017 有一些问题。暂时降级Unity 5.6.4p3

Xcode升级到Xcode9 ,打包会遇到一些问题。Xcode9打包解决方案

8. 下一步

Unity 自动打包 Part2—构建IPA文件

Unity 自动打包 Part3—上传Bugly 邮件通知

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐