 about building build tools to build a tool that builds apps. And I've always wanted to have a talk that was trying to have a ton of twisters, so thanks for humoring me with that. So what I mean by a tool that builds apps is I'm talking about Propeller, which is the company I work for. It looks something like this. So you go to our website and you say, I want to make an app, and we give you this cool kind of WYSIWYT editor that lets you point and click, make customizations, and we show you your native iOS app in the middle of the screen. And we actually make all this happen with review motion, which is really cool. But it's a really hard problem. We have to do a lot of automated builds, a lot of custom libraries, and we're going to talk about how we actually do that. And we're also going to release a couple of new things today, so a couple of new libraries that Ruby Motion developers can benefit from and some stuff that any iOS developer or company can benefit from too. So this is me on a good day. You can stalk me on the internet there. This is Propeller, this is where I work. You guys can stalk us there and learn more about our products and what we do. We deliver apps at scale, because scale is a really badass thing to say. And what I mean by scale is that we ship about 150 apps a month. So if you think shipping one app or two apps to Apple is a pain in the ass, try shipping 150 plus all the updates we do. And this is a totally automated process. We don't go and point and click, which is what I'm going to talk about how we fix. So these are all the GUIs that Apple makes you use. You have Xcode, you have the Apple Developer Center, you have iTunes, Chinette, you have the Applitation Loader. All of these things that are really important to your development process, but they're siloed within GUIs that you don't really have any information about. And that really sucks. If you're a hacker, you're used to having a pipe operator on the command line. You're used to be able to automate processes and make these part of a workflow. But if they're part of a GUI, you can't do any of that. And so it makes you kind of sit down and point and click and do slow stuff. So this is a hard problem. Making and automating GUIs, whether it's websites or native apps, this is stuff that people struggle with every day. And so we've had to trade a lot of custom stuff to fix it. So we kind of did this in two steps. The first step was not to automate it at all and to do things that don't scale. We wanted to validate that people wanted to make apps before we built a bunch of automation. We wanted to make sure we didn't prematurely optimize for stuff that, if it didn't matter, then why would we write a bunch of automation stuff? And the way we did that was I would get an email every time someone submitted an app. And the onus was on me to run a bunch of commands, tape screenshots, put stuff in iTunes, to make it happen. And what I found was I would screw it up a whole lot. I would do things like leave debug code within my working tree, and then when I shipped the app, it would break in weird ways. I would get the descriptions wrong. I would copy, paste things, upload the wrong screenshots. Doing it for one app is totally fine. But when you have one app a day, two apps a day, three apps a day, and now we're doing five apps a day, you just can't do this. This is sort of a way to think about it. There's a bunch of steps. They just take time. We have a ton of apps. And there's some percentage that I'm, or someone's going to mess it up. And at the end of the day, no one has time to do this. Yeah, no one has time to do this because you want to focus on building new things and engineering and not releasing apps all of the time. That's what every organization should strive for. So we got to a point where we just couldn't ship all of the apps that we wanted to ship. And we said, OK, we're going to hit pause. And we're going to build a bunch of automation tools that'll make our lives a lot easier and make our product better. So here's actually all of the steps that you need to build an app. You need to actually code the thing, which is part that we should focus most on. But then you have to do screenshots, testing, bundle identifiers, and provisioning profiles, archiving, iTunes Chinette, application loader. Then you have to actually tell people when it's released. So step one is where you want to spend most of your time in step three. But everything else is just periphery that you have to put up with because of how Apple works and how also Google Play works to a certain degree. And so I'm actually going to walk through each of these and say, here's what we did and here are the tools that we made to make this easier. So the first part is coding the app. This is the fun part. This is where RubyMotion is really, really awesome and much better than the Xcode workflow. You can use rate just like any other type of Ruby command. You can send environment variables and augment your build that way. It has automated testing that reports nicely. It doesn't have any false positives. You can integrate it with continuous integration. Super awesome. It has command line deployment baked in with archiving and releasing. It's a much more command line friendly way to build apps than Xcode. In Xcode, a lot of these settings are kind of hidden in GUIs. You have to build hacks around them. It just doesn't make a whole lot of sense. So RubyMotion is awesome for the build process but also because writing apps in Ruby is a lot more scalable and it's a lot more enjoyable. It's more delightful to work on on a day to day basis and it lets us iterate really fast on new ideas that we have. So in terms of writing code, RubyMotion's awesome. We also have some C-to-it sauce that we use called App Markup. It lets us actually ship a lot of the domain logic for each app from our servers. So if we want to add a feature or fix a bug or something, we can do that without shipping new native code or actually writing it in the first place. So with that, implemented in RubyMotion plus RubyMotion, we're shipping, like I said, 150 apps a month written in RubyMotion to the app store, which is really, really cool. So after you code it, you want to show people what it looks like, like show your customers and users. So you want to take screenshots. You can do this on a device, you can do this using the simulator, but then you have to crop it in Photoshop and it's an arduous process. So we decided to automate it. We made a gym called MotionScreenshots that lets you define the recipes to take all the screenshots for your app and then you can upload them later to iTunes or whatever you want. And it's a really cool API. So how it works is you define your recipe for taking screenshots. In this case, I want to take a screenshot of a profile screen. And so to take this profile screen, I have to tap this row of my view and then once I'm there, I can say ready and they'll take a screenshot. It can be more than just one screenshot per group. You can have a whole flow of like profile screen, messages screen, whatever. And the point of this is to like set up your app in a way that you can do this repeatedly for each new update. So it's really cool. And you trigger this by using the simple start command. When you run this with normal code, it's a no-op. It doesn't do anything. But when you run it under our rate screenshots task, that's when it does the magic. And outputs it in a screenshots folder inside of your app directory. So all you have to do is write your screenshots, runs command, and it'll spit it out in a couple of seconds depending on how long your screenshots take to actually create. It's a gem, super simple. You just sort in your gem file or require it. Go play with it, please. So you've coded it, you've taken screenshots, and now you actually want to test the thing. Testing is really, really important. It's important on iOS to get it right and make sure that your UI looks like what you want it to look like, especially when people expect really high quality interfaces and interactions. So we were thinking like, can we leverage some of the screenshots stuff that we already have and reuse it for our tests? And we came up with motion screen specs, which is a way that you can take screenshots and then compare them to what is actually being tested. So people do this for the web right now, like you take a photo, an image of a web browser, and then you say like, hey, it should be this known truth. And we decided to do this for iOS. So how this works is you reuse the same kind of screenshot API. The exact same file as if you want, or you can create new ones for each UI component that you have. And then you just include it in your specs like this. So you say like, I want to describe my screenshots, and then I want to test them. What this will do when this test runs is execute your screenshots, and then compare them to some expected values, and it'll do a pixel diff. So it'll say like, there are 5% of the pixels are different, so that means something went bad. And you can change that threshold depending on your use case and your type of screenshot. So in this case, I used all of my app screenshots, but we recommend using each component. So if you have a custom view or a custom page, you should actually test this in isolation instead of doing a full blown integration test. It's a good idea. This is what you need to do for the expectations. You create folders within your spec folder that lists which images you want to compare to. And then it'll also output the screenshots it took before, and then do a visual diff on any failures. And the diffs look like this. So you can see I tried to render a news feed. This was over a network connections, so stuff changed a lot. And it gives some information on what went wrong. In this case, everything went wrong. But it can be something as small as the keyboard was offset a little bit, or a color was different. There's a small pixel diff in your labels. It'll catch a lot of really small details, and it's as good as a smoke test for is anything wrong. And it also outputs within a normal rate spec, which is really great, because it'll integrate with CI and run flawlessly. And so in this case, there is a 10% difference. You can tweak these percentages. There's some configuration options for that if you want to have no difference between your expectations, if you want to have some difference. It's a super useful tool. It's another gem. You can go install it and test with more confidence, I guess. So you've written all the code, you've done your screenshots, and you've written really robust tests. You know your thing works, and now you want to actually send it to the app store. So these two steps are a huge pain, because it's totally out of the command line workflow. You've done all this cool work in using Vim or really Sublime or whatever, and I get to open up a web browser and make these things that don't really make a lot of sense, usually. And that sucks. And so we made tools to do this automatically, without having to go through a GUI. And just as a refresher, you use Apple Developer Connection to make your provisioning profiles and bundle identifiers, then you actually create your app on iTunes Chinette, and then you deliver your binary using application loader. And all these things are required every time you want to update or release a new app. So the first thing we did was we created Apple Bot, which is a friendly Apple Developer Connection in iTunes Chinette, like a robot. It's a Ruby and CLI, a Ruby library in CLI that lets you automatically create provisioning profiles and updates on iTunes Chinette, new apps on iTunes Chinette, and do it without having to open a web browser. And the hard part of this is there are other libraries that do this for Apple Developer Center, because those have kind of restful URLs and normal URL schemes. iTunes Chinette is like a really random and nondeterministic in how it generates URLs. It's probably how web objects work underneath the hood or something, but the URLs you get are like long, random streams of integers. They don't make any sense. You can't write a good dependable script without having to actually use a full web striping service to do it. That's what we did. We based it on CasperJS, which is a layer on top of PhantomJS, if any of you are familiar with that. What this means is we can easily debug and maintain web striping strips. The downsides to this are it takes more memory than doing just raw HTTP calls. So it eats about 50 megabytes of memory per instance. And it's also a little slower, because it actually goes and manually fills in each form field, clicks each button, goes to each page, and does the traversal. For iTunes Chinette, there's no better way of doing this that we know of. This is what the API looks like. So you just do a simple require or CLI command and pass in your arguments to everything. Depending on which command, it could take a while to run. So creating an app is 30 or so steps. So you'll be sitting here waiting for it to finish, unless you turn on the verbose flag or something. But it will happen. These are all the commands that it understands right now. So you can do creating apps, removing apps, rejecting apps. You can do the standard, like create app IDs, create provisioning profiles, download them. And we're adding more every week or so for small little tasks that we think should be covered and that we need. You can explore the options on the command line. So creating an app has a lot of flags. You have to do the basic stuff like title and bundle ID, but you also need screenshots, images, icons, keywords, descriptions, content settings, all these lots of settings. And that sucks to enter all of these either in Ruby or on the command line. So that's why you can also pass a JSON manifest file. So you can write one JSON file that says, hey, here's all the info for this update or all the info to create this app and just pass it as an argument. This also lets you do is put your updates inside your version control system. So if you want to bundle your historical updates or you want to ship these to a client and say, hey, fill in your information right here for your description or keywords, you can actually put this within your repo, which is a super cool thing to do. Again, it's a gem. You can use it on your command line, use it in your Rails app, which is what we do. And it requires CasperJS as a dependency. So you can use homebrew or compile it from source or whatever you want to do for that. So you've done the bundle ID and the provisioning profile, and now it's time to actually build the app and upload it. So archiving the app, like I said before, is built into RubyMotion with the archive task. It's really easy. It'll reliably compile it using release mode. If you try to do this with Xcode, it's always kind of like it's part of this target and this schema, and it's just kind of confusing. How we do it, to do it automatically, is we use the combination of these three things. So whenever someone creates a new app, we send a call to GitHub and programatically update a file. So it's sort of like machine's writing code, which is kind of neat. Once that repo gets updated with that new file, it spins out to Travis CI, and Travis CI works awesome with RubyMotion. It's super simple to get up and running, and it can also not just test your apps like CI, but build your apps. So it'll build our app, then we have a strip that'll upload the IPA and the symbol files to our servers, and then we're kind of done with the archiving process, and it's totally hands-free. It's really great. I can talk more, if any of you are interested in that, about how the system works. And the last part is actually uploading an app. If you build an app in Xcode, there's a GUI built-in for like, OK, you've built the app, and now it's time to upload it to the app store. Apple ships another app called Application Loader, which is if you want to upload apps outside of Xcode. It's a native Mac app. There's no API for it. You could reverse engineer it, I guess, but I think it's kind of a pain to do. So what we actually did was we wrote a tool called Apple Load that lets you use Application Loader via the CLI or via Ruby library. And I say use with some hesitance, because via Ruby and CLI, that's a screenshot of what Application Loader looks like, if you're not familiar. I say it lets you use it with some hesitance, because it's actually a bunch of Apple strips that run underneath the hood. Anyone here use Apple Strip before? OK, sweet. So I need to talk to people about how to do this better. Because Apple Strip is this Ruby Strip that generates Apple Strips, and so it's kind of an inception of what's going on. The good thing is that we use it every day, and it works. If it fails, we don't get a lot of good error handling. Like if an app fails to upload because Apple requires a new version of Xcode, we can't extract that very well right now. So it's sort of like a binary, like did the app upload or did the app not upload. So all that aside, the actual API we ship is pretty simple. You can either use it from the command line or from a Ruby library. All you need to do is pass in the app title and the path to your IPA. You could integrate this in your existing projects. You could integrate this in some sort of CLI if you wanted to, or not CLI, but just continuous integration. We think it's really, really cool. And we use it, like I said, every day, and we upload apps. And if things go wrong, we look into why they went wrong. And to Jim, you can use it anywhere you can use Ruby. Super nice. And the last step is you've submitted your app, it's in Apple, it goes through the review process. Either it passes or it fails. They reject it or they accept it. And you actually want to get notifications when this happens. So we wrote another very small library to parse Apple emails that actually extracts information about each submission. And it looks like this. So you pass in whatever your email HTML is, whether you get it from Postmark or Sendred or whatever system. And it'll give you what part of the review it's at, what app version it's talking about, what the app name is, the SKU, it would give you as much information as possible. And so this should be useful to hook up to if this, then that somehow. If you want to do that and say when the app is uploaded or released, notify my clients or do something like that. It's also a gym, you can just install it, use it wherever you use Ruby, it's cool stuff. And so that's how we automated all of the things. So to recap, this is all the steps you need to make an app prior to Ruby Motion and prior to some of the tools we built. It's a huge pain, and then we've kind of filled in all the gaps with our own tooling to make it better. On top of my head, when someone submits an app through us, if it's a clean build, it takes about 45 minutes for the process to finish. And if it's a cache build, then it takes about 15 minutes. And a lot of that time is just Travis downloading resources. If you ever use Travis CI, the CPUs aren't super fast, and their downstream bandwidth is not very fast either, so most of it's actually downloading stuff. We use Travis CI. You can roll your own with your own Mac Mini Rack or do something really badass, but we don't do that. So yeah, it's a really cool system. It's all available on our GitHub. You can go check it out, star it. We have other libraries, two other Ruby Motion libraries. AFMotion's a networking library we host there, some other stuff. So yeah, that's it. If you have any questions about anything I just spewed out or about Bubble Wrap, you can ask me now.