Unity通过PBXProject生成XCode工程

发布时间 2023-04-24 18:59:48作者: muhoor

Unity版本:2020.3.47f1

首先通过PostProcessBuildAttribute监听XCode工程导出完成事件,GetUnityMainTargetGuid是获取XCode工程中"Unity-iPhone"对应的target,GetUnityFrameworkTargetGuid则对应"UnityFramework",在unity中大部分操作会是针对UnityFramework。PBXProject的很多操作都是通过guid的,下面会出现各种各样的guid。

下面是基础代码:

static PBXProject pbxProject;
static string mainTarget;
static string frameworkTarget;
[PostProcessBuildAttribute]
public static void OnPostprocessBuild(BuildTarget buildTarget, string path)
{
    if (buildTarget == BuildTarget.iOS)
    {
        pbxProject = new PBXProject();
        pbxProject.ReadFromString(File.ReadAllText(path));
        mainTarget = pbxProject.GetUnityMainTargetGuid();
        frameworkTarget = pbxProject.GetUnityFrameworkTargetGuid();

    }
}

 

一、BuildSettings

使用SetBuildProperty设置BuildSettings中的设置,参数分别为target、设置名、设置值,其中设置名可以参考这里,比如:

pbxProject.SetBuildProperty(mainTarget, "ENABLE_BITCODE", "NO");
pbxProject.SetBuildProperty(frameworkTarget, "ENABLE_BITCODE", "NO");

如果需要对Debug、Release分别设置,使用BuildConfigByName和SetBuildPropertyForConfig即可,比如:

string debugConfig = pbxProject.BuildConfigByName(mainTarget, "Debug");//Debug、Release、ReleaseForProfiling、ReleaseForRunning
pbxProject.SetBuildPropertyForConfig(debugConfig , "ENABLE_BITCODE", "NO");

 BuildSettings中的所有设置都可以通过上面两个方法设置,包括签名等设置,签名后面单独写。

二、BuildPhases

1、加入至CopyBundleResources

使用AddFile和AddFileToBuild,如下代码,GoogleService-Info.plist与Unity-iPhone.xcodeproj在同一级目录下,下面代码只加到了mainTarget中,如有需要也可加入frameworkTarget

string filePath = "GoogleService-Info.plist";
string fileGuid = pbxProject.AddFile(filePath, filePath, PBXSourceTree.Source);
pbxProject.AddFileToBuild(mainTarget, fileGuid);

2、加入至CompileSources

代码都需要加入到这里,注:AppleLogin.m在Apple目录中,Apple与Unity-iPhone.xcodeproj在同一级目录,不需要对Apple文件夹做任何操作,不要使用"Apple/AppleLogin.m",否则会找不着路径,必须使用Path.Combine。

string filePath = Path.Combine("Apple", "AppleLogin.m");
string fileGuid = pbxProject.AddFile(filePath, filePath, PBXSourceTree.Source);
var sourcesBuildPhase = pbxProject.GetSourcesBuildPhaseByTarget(mainTarget);
pbxProject.AddFileToBuildSection(target, sourcesBuildPhase, fileGuid);

3、LinkBinaryWithLibraries

这块会比较复杂,要分开为4种情况

·系统Framework

使用AddFrameworkToProject,函数很简单,三个参数分别是target、framework名、是否为弱引用,framework名必须以".framework"结尾,弱引用为false时对应xcode中的Required

pbxProject.AddFrameworkToProject(frameworkTarget, "AdSupport.framework", false);

·SwiftPackageManager中的Framework

当工程中用到了SwiftPakcageManager则需要调用以下方法,如下面用到的是Firebase包中的三个framework,Remote相关接口是在Unity2020.3.42新加的,具体可查看官方文档。其中AddRemotePackageFrameworkToProject既是添加到LinkBinaryWithLibraries中,framework的名字不带任何后缀

string firebaseGuid = pbxProject.AddRemotePackageReferenceAtVersion("https://github.com/firebase/firebase-ios-sdk", "10.8.1");
pbxProject.AddRemotePackageFrameworkToProject(frameworkTarget, "FirebaseMessaging", firebaseGuid, false);
pbxProject.AddRemotePackageFrameworkToProject(frameworkTarget, "FirebaseAnalytics", firebaseGuid, false);
pbxProject.AddRemotePackageFrameworkToProject(frameworkTarget, "FirebaseCrashlytics", firebaseGuid, false);

·target作为Framework

由于前面的remoteFramework全部是添加至frameworkTarget中,mainTarget中的代码可能会报错,如果mainTarget中也添加一次,会报两个target中有重复代码的提示,但依然可以编译通过,运行时会有比较诡异的情况发生,比如FirebaseCloudMessaging中的注册token会每次启动都更新,解决方法是把UnityFramework添加至Unity-iPhone的LinkBinaryWithLibraries中,代码如下:

string file = "UnityFramework.framework";
string fileGuid = pbxProject.AddFile(file, file, PBXSourceTree.Build);
if (fileGuid != null)
{
    var sourcesBuildPhase = pbxProject.GetFrameworksBuildPhaseByTarget(mainTarget);
    pbxProject.AddFileToBuildSection(mainTarget, sourcesBuildPhase, fileGuid);
}

·本地Framework

本地Framework也有点特殊,调用的是AddFileToBuild,注:FBAudienceNetwork.framework在sdks目录中,sdks与Unity-iPhone.xcodeproj同一级,不需要单独添加sdks这个目录,否则会找不着所添加的framework

string filePath = Path.Combine("sdks", "FBAudienceNetwork.framework");
string fileGuid = pbxProject.AddFile(filePath, filePath, PBXSourceTree.Source);
pbxProject.AddFileToBuild(frameworkTarget, fileGuid);

三、Info.plist

待续

四、Capabilities

待续

五、签名

待续