- Home /
Is it possible to use the Xcode Manipulation API to add files to the Embedded Binaries build step?
I need to add a framework to the Embed Binaries build step in Xcode. I've asked this before but I think maybe my question was badly phrased or incomplete.
If this is easy, ignore the detailed description below. Thank you!
Within Xcode this is as simple as dragging your framework into the Embedded Binaries area in the targets General page.
This creates a build phase called Embed Frameworks
The project.pbxproj file changes are...
PBXBuildFile section reference added
C5E4C9731BBC78F4007C4CD8 /* MyEmbedded.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = C8FC40EFB7EB18859284D579 /* MyEmbedded.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
PBXCopyFilesBuildPhase section added
C5E4C9741BBC78F4007C4CD8 /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 10;
files = (
C5E4C9731BBC78F4007C4CD8 /* MyEmbedded.framework in Embed Frameworks */,
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
};
PBXNativeTarget section changed to include Embed Frameworks phase
1D6058900D05DD3D006BFB54 /* Unity-iPhone */ = {
isa = PBXNativeTarget;
buildConfigurationList = 1D6058960D05DD3E006BFB54 /* Build configuration list for PBXNativeTarget "Unity-iPhone" */;
buildPhases = (
1D60588D0D05DD3D006BFB54 /* Resources */,
83D0C1FB0E6C8D5900EBCE5D /* ShellScript */,
83D0C1FD0E6C8D7700EBCE5D /* CopyFiles */,
1D60588E0D05DD3D006BFB54 /* Sources */,
1D60588F0D05DD3D006BFB54 /* Frameworks */,
033966F41B18B03000ECD701 /* ShellScript */,
C5E4C9741BBC78F4007C4CD8 /* Embed Frameworks */,
);
buildRules = (
);
dependencies = (
);
name = "Unity-iPhone";
productName = "iPhone-target";
productReference = 1D6058910D05DD3D006BFB54 /* awesumfree.app */;
productType = "com.apple.product-type.application";
};
Finally, and I'm not sure if this is required, XCBuildConfiguration section for all builds (Debug, Release etc.) sets this
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
Hopefully this is detailed enough to get me an answer. I'd really love to be able to build this with Cloud Build but that will only work if I can set this stuff up in a PostProcessBuild function.
Just adding a link to the forum thread. http://forum.unity3d.com/threads/is-it-possible-to-use-the-xcode-manipulation-api-to-add-files-to-the-embedded-binaries-build-step.358357/
Answer by mihakinova · Jul 07, 2017 at 09:54 AM
So after a lot of messing around I finally got this to work. This is basically what @tarasfromlviv wrote with a few modifications. Here's how to do it:
Clone Unity's XcodeAPI: https://bitbucket.org/Unity-Technologies/xcodeapi (Note, it's a mercurial repository, not Git). I also changed the namespace of all the files to include my prefix, so I can distinguish it from the build in version, something like "Custom.UnityEditor.iOS.Xcode"
To the PBXProject.cs file add the following method:
public void AddDynamicFrameworkToProject(string targetGuid, string frameworkPathInProject) { var fileGuid = FindFileGuidByProjectPath(frameworkPathInProject); if (fileGuid == null) { Debug.LogError("Framework not found: " + frameworkPathInProject); return; } // add file reference as embed framework PBXBuildFileData embedFrameworkFileData = PBXBuildFileData.CreateFromFile(fileGuid, false, ""); BuildFilesAdd(targetGuid, embedFrameworkFileData); // add "Embed Frameworks" section // TODO: check if exists PBXCopyFilesBuildPhaseData embedFrameworksSection = PBXCopyFilesBuildPhaseData.Create("Embed Frameworks", "", "10"); embedFrameworksSection.files.AddGUID(embedFrameworkFileData.guid); m_Data.copyFiles.AddEntry(embedFrameworksSection); // add "Embed Frameworks" section to "Build phases" PBXNativeTargetData target = nativeTargets[targetGuid]; target.phases.AddGUID(embedFrameworksSection.guid); }
Add this to your build script:
[PostProcessBuild] public static void OnPostProcessBuild(BuildTarget buildTarget, string path) { if (buildTarget == BuildTarget.iOS) { string projectPath = path + "/Unity-iPhone.xcodeproj/project.pbxproj"; PBXProject pbxProject = new PBXProject(); pbxProject.ReadFromFile(projectPath); string target = pbxProject.TargetGuidByName("Unity-iPhone"); // pbxProject.SetBuildProperty(target, "ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES", "YES"); pbxProject.SetBuildProperty(target, "LD_RUNPATH_SEARCH_PATHS", "$(inherited) @executable_path/Frameworks"); AddDynamicFrameworks(ref pbxProject, target); pbxProject.WriteToFile(projectPath); string contents = File.ReadAllText(projectPath); // Enable CodeSignOnCopy for the framework contents = Regex.Replace(contents, "(?<=Embed Frameworks)(?:.*)(\\/\\* EXAMPLE\\.framework \\*\\/)(?=; };)", m => m.Value.Replace("/* EXAMPLE.framework */", "/* EXAMPLE.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }")); File.WriteAllText(projectPath, contents); } } static void AddDynamicFrameworks(ref PBXProject project, string target) { const string defaultLocationInProj = "Frameworks/Plugins/iOS"; const string coreFrameworkName = "EXAMPLE.framework"; string relativeCoreFrameworkPath = Path.Combine(defaultLocationInProj, coreFrameworkName); project.AddDynamicFrameworkToProject(target, relativeCoreFrameworkPath); Debug.Log("Dynamic Frameworks added to Embedded binaries."); }
Replace "EXAMPLE" (and nothing else) in the code above to the name of your framework.
And voila, Unity will now add your framework to Embedded Binaries automatically!
I still, for the life of me, can't figure out why this is not natively supported...
Should "HondaProxy.framework" be "EXA$$anonymous$$PL$$anonymous$$framework"??
Correct, thanks, modified the example. Just a note, this is now mostly obsolete as Unity added a built-in way to add dynamic frameworks.
I haven't found any other ways of doing CodeSignOnCopy, still using your regex above
Hmm, CodeSignOnCopy should work automatically. If you check PBXProjectExtensions.AddFileToEmbedFrameworks you can see there's a codeSignOnCopy = true
in there. There are a couple of other settings / properties I had to set to get it to work properly though. Here is an excerpt from my build script that adds the frameworks: https://pastebin.com/hqV$$anonymous$$SQgV
Btw, my frameworks are located in Assets/Plugins/iOS/EXA$$anonymous$$PL$$anonymous$$framework.
Answer by tarasfromlviv · Jan 12, 2017 at 03:32 PM
So, clone Unity official XCode API and apply this modifications, this will basically add existing frameworks in your project to embedded binaries:
Inside PBXProject:
public void AddDynamicFrameworkToProject(string targetGuid, string frameworkPathInProject)
{
var fileGuid = FindFileGuidByProjectPath(frameworkPathInProject);
if (fileGuid == null)
{
Debug.LogError("GetSocial Framework not found: " + frameworkPathInProject);
return;
}
// add file reference as embed framework
PBXBuildFileData embedFrameworkFileData = PBXBuildFileData.CreateFromFramework(fileGuid);
BuildFilesAdd(targetGuid, embedFrameworkFileData);
// add "Embed Frameworks" section
// TODO: check if exists
PBXCopyFilesBuildPhaseData embedFrameworksSection = PBXCopyFilesBuildPhaseData.Create("Embed Frameworks", "10");
embedFrameworksSection.files.AddGUID(embedFrameworkFileData.guid);
m_Data.copyFiles.AddEntry(embedFrameworksSection);
// add "Embed Frameworks" section to "Build phases"
PBXNativeTargetData target = nativeTargets[targetGuid];
target.phases.AddGUID(embedFrameworksSection.guid);
}
Usage Example:
static void AddDynamicFrameworks(PBXProject project, string target)
{
const string defaultLocationInProj = "Frameworks/Plugins/iOS";
const string coreFrameworkName = "GetSocial/GetSocial.framework";
const string uiFrameworkName = "GetSocialUI/GetSocialUI.framework";
string relativeCoreFrameworkPath = Path.Combine(defaultLocationInProj, coreFrameworkName);
string relativeUiFrameworkPath = Path.Combine(defaultLocationInProj, uiFrameworkName);
project.AddDynamicFrameworkToProject(target, relativeCoreFrameworkPath);
project.AddDynamicFrameworkToProject(target, relativeUiFrameworkPath);
Debug.Log("GetSocial Dynamic Frameworks added to Embedded binaries.");
}
Hey, that seems pretty helpful! Any chance of you submitting a pull request to the UnityTechnologies/Unity/XcodeAPI repo?
I tried adding your patch using the latest pull from their repo, but compiler complains that PBXBuildFileData. CreateFromFramework
doesn't exist. Was that another method you added?
Answer by zfavourite99 · Feb 08, 2018 at 08:10 AM
#if UNITY_EDITOR_OSX
using UnityEditor.iOS.Xcode;
using UnityEditor.iOS.Xcode.Extensions;
#endif
public class TestBuildPostprocessor {
[PostProcessBuildAttribute(1)]
public static void OnPostprocessBuild(BuildTarget target, string pathToBuiltProject) {
if (target != BuildTarget.iOS) {
UnityEngine.Debug.LogWarning ("Target is not iPhone. XCodePostProcess will not run");
return;
}
#if UNITY_EDITOR_OSX
//EmbedFrameworks
string projPath = PBXProject.GetPBXProjectPath(pathToBuiltProject);
PBXProject proj = new PBXProject();
proj.ReadFromString(File.ReadAllText(projPath));
string targetGuid = proj.TargetGuidByName("Unity-iPhone");
const string defaultLocationInProj = "Plugins/iOS";
const string coreFrameworkName = "test.framework";
string framework = Path.Combine(defaultLocationInProj, coreFrameworkName);
string fileGuid = proj.AddFile(framework, "Frameworks/" + framework, PBXSourceTree.Sdk);
PBXProjectExtensions.AddFileToEmbedFrameworks(proj, targetGuid, fileGuid);
proj.SetBuildProperty(targetGuid, "LD_RUNPATH_SEARCH_PATHS", "$(inherited) @executable_path/Frameworks");
proj.WriteToFile (projPath);
//EmbedFrameworks end
#endif
}
}
this code work for me!
Just an FYI, you don't need #if UNITY_EDITOR_OSX to use the Xcode manipulation framework. You can use it on windows just fine, and unity will be able to generate the Xcode project (afaik), you just won't be able to build it to an IPA file.
Answer by unity_GYs5GCE8dSeS8A · Jun 15, 2019 at 07:02 AM
I use your file for adding Embedded Binaries file. But recently I have a framework which used alias files. When xcodeproj got ready I see just one alias file on my framework folder. The framework which I tried to add is Pushwoosh. Do you have any idea how should I do it?
Thanks for your consideration
Answer by David-Berger · Oct 06, 2015 at 03:56 PM
It does not look like this is possible yet via XCode Manipulation API, but it could be added as it's open source.
Edit: The forum thread is here: http://forum.unity3d.com/threads/is-it-possible-to-use-the-xcode-manipulation-api-to-add-files-to-the-embedded-binaries-build-step.358357/
Your answer
Follow this Question
Related Questions
Bluetooth Description in Xcode 0 Answers
Distribute terrain in zones 3 Answers
Is the Cloud Build API key machine specific? 0 Answers
Invalid PBX project Unity 5 0 Answers
Building to IOS 2 Answers