iOS Plugin -- How to link iOS framework?

I have made an iOS plug-in that uses Accelerate framework.

When I build and run, Unity launches Xcode which fails with “Missing symbol…” errors.

Of course this can be fixed by manually adding the Accelerate framework to the target each time from within Xcode. But this makes for a hopeless build cycle.

Someone has posted exactly the same question here but he doesn’t come into detail of how he solves it.

He does however mention PostprocessBuildPlayer

I have found a PostprocessBuildPlayer script by Akisute that claims to do exactly what I want.

I created a file: Assets/Editor/PostprocessBuildPlayer into which I pasted Akisute’s script, modifying the necessary line to include Accelerate framework:

:
:
#
# Add System frameworks required to build
#
projpath = buildpath + "/Unity-iPhone.xcodeproj"
proj = Xcodeproj::Project.new(projpath)

#add_system_frameworks_to_project(proj, ["StoreKit", "Security", "CoreText", "MessageUI"], :required)
#add_system_frameworks_to_project(proj, ["Twitter", "Social"], :optional)

add_system_frameworks_to_project(proj, ["Accelerate"], :required)

proj.save_as(projpath)

Unfortunately it doesn’t work. Xcode appears to fail in exactly the same manner as it did before I tried the script.

Can anyone help me towards getting this working? I’m quite surprised I can’t find any literature on the inter-webs; surely this must be quite a common task…

EDIT: applying Google translate to the author’s website, I notice a note saying I should first run

sudo gem install xcodeproj

from the terminal. However, if I do this it hangs the terminal session.

EDIT: After installing / updating a ton of stuff; homebrew, Xcode commandline tools, Ruby (and God knows what else), I successfully installed that above program. still no luck. I look in the editor.log. the ruby script prints some stuff to the console, e.g.:

puts "PostprocessBuildPlayer running on build directory: " + buildpath

Here is the EDITOR LOG

Hi PI, here’s an original author of the article you saw :slight_smile:

I reviewed your EDITOR LOG and found that you have failed to install xcodeproj module on Ruby, indicated in the log:

2012-10-27 05:27:49.539 Unity[193:1903] Checking <NSRunningApplication: 0x3505f680 (com.apple.dt.Xcode - 251)>
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/rubygems/custom_require.rb:31:in `gem_original_require': no such file to load -- xcodeproj (LoadError)
        from /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/rubygems/custom_require.rb:31:in `require'
        from /Users/sunfish7/Desktop/UnityProjGroups/A_MiscTests/A7_iOS_Plugin/C_StreamerFFTPlugin/Assets/Editor/PostprocessBuildPlayer:14

My PostprocessBuildPlayer runs Ruby and its module named “xcodeproj” in order to automatically modify the Xcode Project generated by Unity and that’s why you have to install it. Damn complicated, but there’s no choice.

That said, here’s how you can fix this. First, check your Ruby installation by following commands

which ruby
which gem
gem list --local

and make sure xcodeproj is installed on your gem like this:

akisute ~$ gem list --local

*** LOCAL GEMS ***

xcodeproj (0.3.2)

I suspect you might have installed Ruby via homebrew, while your EDITOR LOG indicates the PostprocessBuildPlayer ran the System Ruby (The default Ruby installed on OS X). You can either install xcodeproj on System Ruby by

sudo /usr/bin/gem install xcodeproj

or have your PostprocessBuildPlayer use homebrew Ruby by modifing the first line of the PostprocessBuildPlayer like this:

#!/somewhere/else/your/homebrew/ruby_is_installed/ruby

Hope this works!

Hey Akisute! Thank you so much for replying.

I tried your first suggestion, and got an error (here)

Someone on IRC tells me this is because my path cannot find a compiler that supports the ‘–std=c99’ option. I’m a little confused about this because I went through a long process of installing Ruby through homebrew (here), and I think one of the steps (Step 5: ‘rvm install 1.9.2’ ) took me through installing the old GCC compiler so that it could compile sources for RVM. So I would have thought this command could access that compiler.

I tried your second suggestion, and it works!!! No ‘missing symbol’ errors from XCode. This is wonderful!

I notice your script logs to the console, e.g.:

puts "PostprocessBuildPlayer running on build directory: " + buildpath

But looking through my ~/Library/Logs/Unity/Editor.log (here) I can’t find that line.

Where should it get logged?

I have added a Feature Request to address this. If you are interested in helping it get noticed then you can view it here:

Unity Feature Request

1 Like

I used this solution: build the project, copy the project file, then add the framework in xcode and compare the project file to the old one we saved… (svn merge, whatever you like…) Now you can see the difference that you need to add. Of course you can go around the string editing part in many ways… I chose the most stupid one :slight_smile: I “Replace()” the above/below line to my desired framework with that framework.

    using UnityEngine;
    using UnityEditor;
    using UnityEditor.Callbacks;
    using System.Collections;
    using System.IO;
  
    public class PostprocessBuildPlayer
    {
  
        [PostProcessBuild]
        public static void OnPostprocessBuild(BuildTarget target, string pathToBuiltProject)
        {
            LinkLibraries(target, pathToBuiltProject);
  
        }
  
        //
        public static void LinkLibraries(BuildTarget target, string pathToBuiltProject)
        {
            if(target == BuildTarget.iPhone)
            {
                string projectFile = pathToBuiltProject+"/Unity-iPhone.xcodeproj/project.pbxproj";
                string contents = File.ReadAllText(projectFile);
  
                // StoreKit.framework
                contents = contents.Replace("Ref = 8AFA69D8161605E7009663A5 /* iPhone_OrientationSupport.mm */; };",
                    "Ref = 8AFA69D8161605E7009663A5 /* iPhone_OrientationSupport.mm */; };\n\t\t9AA477301A1F575F00974444 /* StoreKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9AA4772F1A1F575F00974444 /* StoreKit.framework */; };");
                contents = contents.Replace("wnFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };",
                    "wnFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\t9AA4772F1A1F575F00974444 /* StoreKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = StoreKit.framework; path = System/Library/Frameworks/StoreKit.framework; sourceTree = SDKROOT; };");
                contents = contents.Replace("1D60589F0D05DD5A006BFB54 /* Foundation.framework in Frameworks */,",
                    "9AA477301A1F575F00974444 /* StoreKit.framework in Frameworks */,\n\t\t\t\t1D60589F0D05DD5A006BFB54 /* Foundation.framework in Frameworks */,");
                contents = contents.Replace("8358D1B70ED1CC3700E3A684 /* AudioToolbox.framework */,",
                    "9AA4772F1A1F575F00974444 /* StoreKit.framework */,\n\t\t\t\t8358D1B70ED1CC3700E3A684 /* AudioToolbox.framework */,");
  
                File.WriteAllText(projectFile, contents);
            }
        }
    }

Edit: Idea based on stuff that i found with google, similar to previous answers - just less complicated.

Hello 2012 people! I’m in 2014 and this issue seems to be 100% ignored still by UT.

3 Likes