/ 开发笔记

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

问题环境

之前用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