Vendor – Bringing Bundler to iOS

Using and sharing iOS libraries is tragically difficult given the maturity of the framework, the number of active developers, and the size of the open source community.  Compare with Rails which has RubyGems and Bundler, it’s no surprise that Rails/Ruby has a resource like The Ruby Toolbox, while iOS development has…nothing?

Are iOS developers fundamentally less collaborative than Rails developers?  When developing on Rails, if I ever find myself developing anything remotely reusable, I can almost always be certain that there is a gem for it (probably with an obnoxiously clever name).

I don’t think the spirit of collaboration is lacking in the iOS developer community; rather, there are a few fundamental challenges with iOS library development:

  • Libraries are hard to integrate into a project.  Granted, it’s not *that* hard to follow a brief set of instructions, but why can’t this process be more streamlined?
  • No standardized versioning standard.  Once a library is integrated into a project, there is no standard way of capturing which version of the library was used.
  • No dependency specification standard (this is a big problem).  Why does facebook-ios-sdk embed it’s own JSON library when there are better ones available?  So many libraries come embedded with common libraries that we all use – and worse than that, who knows what version they’re using!  Not only can this lead to duplicate symbols, but library developers essentially have to start from scratch instead of leveraging other existing libraries.

Of course, coming up with a naming, versioning, and dependency standard for iOS libraries and convincing everyone to adopt it is a daunting task.  One possible approach is follow the example of Homebrew, a popular package manager for OS X.  Homebrew turned installing and updating packages on OS X into a simple process.  Instead of convincing everyone to comply to some standard, Homebrew maintains a set of formulas that helps describe commonly used packages.  These formulas allow Homebrew to automate the installation process as well as enforce dependencies.  This works well for Homebrew, although it puts the burden of maintaining package specifications in one place, rather then distributed as it is with Ruby gems.

There seems to be a need for some type of solution here.  When we write Rails libraries, we write the readme first to help us understand what problem we’re trying to solve (Readme Driven Development).  Below is the readme for an iOS packaging system called Vendor.

Vendor – an iOS library management system

Vendor makes the process of using and managing libraries in iOS easy.  Vendor leverages the XCode Workspaces feature introduced with XCode 4 and is modeled after Bundler. Vendor streamlines the installation and update process for dependent libraries.  It also tracks versions and manages dependencies between libraries.

Step 1) Specify dependencies

Specify your dependencies in a Vendors file in your project’s root.

source "https://github.com/bazaarlabs/vendor"
lib "facebook-ios-sdk"  # Formula specified at source above
lib "three20"
lib "asi-http-request", :git => "https://github.com/pokeb/asi-http-request.git"
lib "JSONKit", :git => "https://github.com/johnezang/JSONKit.git"

Step 2) Install dependencies

vendor install
git add Vendors.lock

Installing a vendor library gets the latest version of the code, and adds the XCode project to the workspace.  As part of the installation process, the library is set up as a dependency of the main project, header search paths are modified, and required frameworks are added.  The installed version of the library is captured in the Vendors.lock file.

After a fresh check out of a project from source control, the XCode workspace may contain links to projects that don’t exist in the file system because vendor projects are not checked into source control. Run `vendor install` to restore the vendor projects.

Other commands

# Updating all dependencies will update all libraries to their latest versions.
vendor update
# Specifying the dependency will cause only the single library to be updated.
vendor update facebook-ios-sdk

Adding a library formula

If a library has no framework dependencies, has no required additional compiler/linker flags, and has an XCode project, it doesn’t require a Vendor formula. An example is JSONKit, which may be specified as below. However, if another Vendor library requires JSONKit, JSONKit must have a Vendor formula.

lib "JSONKit", :git => "https://github.com/johnezang/JSONKit.git"

However, if the library requires frameworks or has dependencies on other Vendor libraries, it must have a Vendor formula.  As with Brew, a Vendor formula is some declarative Ruby code that is open source and centrally managed.

An example Vendor formula might look like:

require 'formula'

class Three20 < Formula
  url "https://github.com/facebook/three20"
  libraries libThree20.a
  frameworks "CoreAnimation"
  header_path "three20/Build/Products/three20"
  linker_flags "ObjC", "all_load"
  vendors "JSONKit"
end

Conclusion

Using iOS libraries is way harder than it should be, which has negatively impacted the growth of the open source community for iOS.  Even if I was only developing libraries for myself, I would still want some kind of packaging system to help me manage the code.  Vendor essentially streamlines the flow described by Jonas Williams here.  Unfortunately, programmatically managing XCode projects isn’t supported natively, but people have implemented various solutions, such as Three20Victor Costan, and XCS.

Open Questions

  • Is there an existing solution for this?
  • Would this be a useful gem for your iOS development?
  • Why hasn’t anyone built something like this already? Impossible to build?
This entry was posted in All, Engineering. Follow any comments here with the RSS feed for this post. Post a comment or leave a trackback: Trackback URL.

Add a Comment

Your email is never published nor shared.

*
*

18 Comments

  1. Sounds like a good challenge.

    >Is there an existing solution for this?
    no

    >Would this be a useful gem for your iOS development?
    of course

    >Why hasn’t anyone built something like this already? Impossible to build?
    I think that the main reasons are:
    1. everyone waiting solution from Apple that will become standard
    2. there is no specification for *.xcodeproject file format

    1. timothy1ee says:

      Cool, thanks for the feedback. Yes, manipulation of the xcodeproject does seem to be at least one of the major pain points, although people have hacked ways around it. Three20 has reverse engineered the file format, while others have used Applescript to manipulate the project file. Personally, I’m leaning towards the Applescript approach.

  2. Nate says:

    This would be brilliant. We’ve struggled with this exact problem for months now and have resorted to rake tasks for building up dependencies. A formal approach is something that is sorely lacking in the iOS world.

  3. I thought again and I think that the best way is:

    1. create analog of Ruby Gems and rubygems.org
    2. each vendor packackage will contain a static library compiled for ARM and iOS Simulator (x86) with all it header files
    3. format of vendor package will be similar to ruby gem with ability to specify version, author, dependencies, etc.
    4. in root of Xcode project will be located Vendor file with list of all frameworks and static libraries used in project
    5. `vendor install` will download all needed vendor packages and modify Xcode project to link with all frameworks, static libraries, add header search path for each vendor package

    What do You think about this? I’m very interested in development of this kind of system, would You participate?

    1. timothy1ee says:

      I’m doing some proof of concept work on this tomorrow. If it works out, I’ll open source it, and if you’re interested in collaborating, that would be great.

      1. I have one question:

        we know that for iOS we can use only static libraries. For example, I have a 3 projects

        1) SBJSON
        2) Facebook iOS SDK
        3) RestKit

        2) and 3) depends on 1).

        When 2) and 3) will be complied can we make that they will link dynamically against 1) but iOS app will be statically linked with 1), 2) and 3) ?

      2. Hey Timothy!

        I’m very interested in participating on this project. If You need any help please drop me a line on igor.evsukov@gmail.com

  4. keithpittt says:

    Hey Tim,
    I’ve almost finished an alpha of this project. I’ll drop you a line when I’ve got something working. I’ve actively developing this at the moment. Send me an email and I’ll show you what I’ve done so far.

    1. Nate says:

      I’m definitely interested. Have a Github repo yet?

      1. Jake says:

        Looks like his link is here: https://github.com/keithpitt/VendorKit

        I have been thinking on this and is there any reason we don’t jus use bundler itself?

        We can build gemspecs that build static libraries as described here also: http://blog.carbonfive.com/2011/04/04/using-open-source-static-libraries-in-xcode-4/

  5. timothy1ee says:

    @Jake, that’s exactly what I was thinking. i.e., ensure that libraries conform to the standard described in http://blog.carbonfive.com/2011/04/04/using-open-source-static-libraries-in-xcode-4/, using XCode Workspaces.

    How would we use bundler itself though?

    1. Jake says:

      @Tim if we include a .gemspec in each library’s root, bundler and rubygems should be able to build the library.

      We would create a Gemfile with the libraries we want to include and then just run bundle install. We can have a separate source and index for objective-c projects so we do not need to submit the libraries to rubygems.org

      There might be some hangups with doing it this way, but theoretically it should work.

  6. Jake says:

    Also, there is now this project which seems in this vein: https://github.com/alloy/cocoapods

  7. keithpitt says:

    For those that are still interested, I finished making this:

    https://github.com/keithpitt/vendor

    It all works, and I’ve successfully been using it in my projects for a while now :D

    1. nesquena says:

      Project looks great and so does the website. Nice work man, really excited to use it in future projects.

    2. timothy1ee says:

      Keith, this looks fantastic, will definitely try it out!

  8. [...] them. The great example I want to share, it’s we found out earlier this week that one of our blog post has been an inspiration for [...]

  9. marketing is the wave of the future generations of alcoholics I pray that AA remain strong.
    They first had to learn everything I could about the stock
    market.

  10. Hey, I just want to provide a simple notice to help you
    realize that some of the graphics aren’t properly showing successfully on this internet site. I have no idea the reasons why but I think that you’ll find it’s a linking factor. I even tried it in two other internet browsers and both still provide an identical final result.

One Trackback

  1. [...] them. The great example I want to share, it’s we found out earlier this week that one of our blog post has been an inspiration for [...]