How can I programmatically add a run script build phase to an Xcode project?
Asked Answered
A

4

11

I am wondering if it is possible to add a run script build phase to another Xcode project from within my Mac utility app. I can see what takes place in an Xcode project when a run script is added (doing a diff), but I don't know how to safely add the equivalent in code.

Am I supposed to parse it manually? Is there documentation or libraries available for this? This would be a useful feature if I can make sure I do it safely and right. I don't want to be messing up people's Xcode projects!

Allimportant answered 10/10, 2013 at 17:13 Comment(0)
A
2

I actually decided to add a run script. It turned out to be quite easy. First, in Xcode, add a run script to your project and observe the changes via the diff tool. There is an addition to the 'buildPhases' array (which is nested down pretty deep in some arbitrarily named dictionaries), and then the key that was added to the 'buildPhases' array was also added to the 'objects' dictionary with a dictionary that represents the actual run script build phase format.

So to replicate this programmatically, get the contents of the pbxproj file into an NSDictionary, and iterate through the dictionaries looking for the buildPhases array. Then, add your key. Finally, add an object to the 'objects' array with the key and a dictionary that mirrors the format in Xcode.

Save the file back to disk in the same location and voila! You have programmatically added a run script build phase.

Allimportant answered 14/10, 2013 at 22:10 Comment(1)
When/what do you run this code with? is it a swift script? do you mind sharing it here or as a gist or something?Bennettbenni
I
8

For anyone looking for the easy way to do this, there is a great python library that lets you mod all types of things in the .pbxproj file. You can check it out here: https://github.com/kronenthaler/mod-pbxproj.

Now to add a run script build phase you can write a simple python script like:

from pbxproj import XcodeProject
import sys

project = XcodeProject.load('path/to/my-project.xcodeproj/project.pbxproj')
project.add_run_script('bash my_run_script.sh')
project.save()

Now just run the python script and you should be good to go.

Incudes answered 26/4, 2018 at 14:31 Comment(1)
I run the script and completely messed up with my projectSphygmoid
S
5

My solution requires a little bit of ruby knowledge. There is a library called xcodeproj that it is included with Cocoapods

sudo gem install cocoapods

or,

gem install xcodeproj

To install only the library.

To create a ruby file that adds a run script phase into your targets:

require 'xcodeproj'

project = Xcodeproj::Project.open "./TargetTest.xcodeproj"

for target in project.targets 
    puts "Target -> " + target.name
    phase = target.shell_script_build_phases().find {|item| item.name == "My run phase"}
    if (phase.nil?)
        puts "Creating script 'My run phase'"
        phase = target.new_shell_script_build_phase("My run phase")
        phase.shell_script = "echo Hello script"
    else
        puts "'My run phase' already exist"
        phase.shell_script = "echo modified"
    end
end

project.save() 

And you can run it:

ruby add_run_phase_script.rb

Edit: Replace "=" with "==" in find, otherwise the first script will be replaced, and we need an append

Sphygmoid answered 22/4, 2020 at 9:32 Comment(0)
G
3

The possibly easiest solution is to add a Run Script Phase to the other Project which defines a command line executing a script which resides as a particular file in some known location.

The first project then may have a Run Script Phase, or execute a program which creates or modifies this script file. When the other project starts, it starts the Run Script Phase and - voilà - executes whatever has been defined.

Grimbal answered 10/10, 2013 at 17:32 Comment(4)
Thanks for the answer! Still trying to wrap my head around it :). My Mac app is on the store, and is what I am trying to do is have a button in my app, that adds a Run Script Phase to whatever project the user has specified on the file system. It needs to be at run time. Would the terminal still be by best option?Allimportant
Well, this may become complex (fiddling in the XML of Xcode projects). Perhaps, a preliminary solution would be that your app creates a script file, and that it tells the user how to execute that script file in a Run Script Phase. This Run Script Phase needs to be added by the user in his project.Grimbal
Fair enough. The purpose of this question was to see if it was possible and feasible. I don't want to risk corruption with people's project files and so it may be better to look for a work around. Thanks!Allimportant
Your welcome, and me too would get gripes when I know the utility app fiddles with my Xcode project ... ;)Grimbal
A
2

I actually decided to add a run script. It turned out to be quite easy. First, in Xcode, add a run script to your project and observe the changes via the diff tool. There is an addition to the 'buildPhases' array (which is nested down pretty deep in some arbitrarily named dictionaries), and then the key that was added to the 'buildPhases' array was also added to the 'objects' dictionary with a dictionary that represents the actual run script build phase format.

So to replicate this programmatically, get the contents of the pbxproj file into an NSDictionary, and iterate through the dictionaries looking for the buildPhases array. Then, add your key. Finally, add an object to the 'objects' array with the key and a dictionary that mirrors the format in Xcode.

Save the file back to disk in the same location and voila! You have programmatically added a run script build phase.

Allimportant answered 14/10, 2013 at 22:10 Comment(1)
When/what do you run this code with? is it a swift script? do you mind sharing it here or as a gist or something?Bennettbenni

© 2022 - 2025 — McMap. All rights reserved.