#Unity# 在编辑器扩展中用PostProcessBuildAttribute来修改XCode工程的Product Name

利用Unity编辑器脚本来自动修改XCode工程

问题环境

之前用Unity打包上传时遇到过一个问题:
#Unity# iOS打包上传时报错 The bundle uses a bundle name or display name that is already taken

在解决这个bundle name冲突的时候,提到需要手动修改Product Name,以避免与系统名字冲突。

但是,Unity输出工程时,每次都会覆盖这些设置,如果每次手动修改还是挺麻烦的。

那么,有没有办法可以自动化呢?

解决方法

自动化的方法,就是利用Unity的编辑器扩展脚本,参考另一篇文章:

#Unity# 通过扩展编辑器实现快速输出iOS工程

再加上Unity提供的打包工作流脚本插件
PostProcessBuildAttribute: Add this attribute to a method to get a notification just after building the player.

利用这个脚本,就可以在打包的时候对XCode工程进行修改了。

要点讲解

  1. 格式
    声明打包后需要执行的方法:
[PostProcessBuildAttribute]
public static void OnPostProcessBuild(BuildTarget target, string pathToBuildProject)
{

}

  1. 修改xcode 工程文件

1). 打开xcode工程

string pbxProjectPath = PBXProject.GetPBXProjectPath( pathToBuildProject );
	// 修改工程设置
	PBXProject pbxProject = new PBXProject();
	pbxProject.ReadFromFile( pbxProjectPath );

2). 读取设置,这里读取 PRODUCT_BUNDLE_IDENTIFIER 和 PRODUCT_NAME

PBXProject pbxProject = new PBXProject();
pbxProject.ReadFromFile( pbxProjectPath );

// 读取 build target string targetGUID = pbxProject.TargetGuidByName(PBXProject.GetUnityTargetName() );

// 读取具体属性设置 var bundleId = pbxProject.GetBuildPropertyForAnyConfig(targetGUID, “PRODUCT_BUNDLE_IDENTIFIER”);

var productName = pbxProject.GetBuildPropertyForAnyConfig(targetGUID, “PRODUCT_NAME”);

3). 修改设置

string newProductName = "doufxcamera"; // 注意product name必须都小写

if(productName != newProductName){ pbxProject.SetBuildProperty(targetGUID, “PRODUCT_NAME”, newProductName); }

4). 保存

File.WriteAllText( pbxProjectPath, pbxProject.WriteToString() );
  1. 修改Info.plist文件

注意:如果只修改PRODUCT_NAME,会发现我们设置的BundleId也被修改了,因为Unity的XCode工程中,Info.plist中BundleId是与PRODUCT_NAME相关的。

Unity_Edit_XCode_Project_Using_Script

步骤与修改工程文件类似
1). 打开文件

string plistPath = Path.Combine( pathToBuildProject, "Info.plist" );
PlistDocument plist = new PlistDocument();
plist.ReadFromString( File.ReadAllText( plistPath ) );

PlistElementDict rootDict = plist.root;

2). 读取或者修改字段

rootDict.SetString("CFBundleIdentifier", bundleId);

3). 保存

File.WriteAllText( plistPath, plist.WriteToString() );
  1. 完整代码参考
[PostProcessBuildAttribute]
public static void OnPostProcessBuild(BuildTarget target, string pathToBuildProject)
{
	if (target == BuildTarget.iOS)
	{
		Debug.Log( "[PostBuild] pathToBuildProject: " + pathToBuildProject );
	string pbxProjectPath = PBXProject.GetPBXProjectPath( pathToBuildProject );

    // 修改工程设置
	PBXProject pbxProject = new PBXProject();
	pbxProject.ReadFromFile( pbxProjectPath );

	string targetGUID = pbxProject.TargetGuidByName( PBXProject.GetUnityTargetName() );
	var bundleId = pbxProject.GetBuildPropertyForAnyConfig(targetGUID, "PRODUCT_BUNDLE_IDENTIFIER");
	var productName = pbxProject.GetBuildPropertyForAnyConfig(targetGUID, "PRODUCT_NAME");
	
    string newProductName = "doufxcamera";

	Debug.LogFormat("[PostBuild] bundleid = {0}, product name={1}, change product name to: {2}", bundleId, productName, newProductName);
	
    if(productName != newProductName){
		pbxProject.SetBuildProperty(targetGUID, "PRODUCT_NAME", newProductName);
	}
	
    File.WriteAllText( pbxProjectPath, pbxProject.WriteToString() );

	// 修改plist
	string plistPath = Path.Combine( pathToBuildProject, "Info.plist" );
	PlistDocument plist = new PlistDocument();
	plist.ReadFromString( File.ReadAllText( plistPath ) );

	PlistElementDict rootDict = plist.root;
	rootDict.SetString("CFBundleIdentifier", bundleId);
                
    File.WriteAllText( plistPath, plist.WriteToString() );
}

}

参考

  1. https://docs.unity3d.com/ScriptReference/iOS.Xcode.PBXProject.UpdateBuildProperty.html
  2. https://docs.unity3d.com/ScriptReference/iOS.Xcode.PBXProject.html