Doios robert van loghem cover?fm=jpg&fl=progressive&q=75&w=300

Let Your Designer Tweak and Deploy Your App

Building apps is fun, but tweaking the UI can be cumbersome. Designers love to tweak, but would it not be nice if they could make changes to the UI and distribute a version of the app for testing? With hosted SCM, build and distribution tools like GitHub, Carthage/CocoaPods, Fastlane, Crashlytics and hosted Continuous integration server Bitrise, it is now possible to let them design and tweak to their heart’s content. At do{iOS} 2015, Robert van Loghem explains how to set up fully automated continuous delivery for your app, and how not-so-technical people can make changes and deliver the app to Crashlytics, Appetize.io, Testflight and even the App Store.

The best apps are created by experimentation and constant tweaking: getting the app in your hand, and seeing how it feels.

Meet Mio, My Designer (1:06)

Mio is my designer. I love working with designers. They have many requests to which I respond, but it would be great if they could be independent (e.g. not using a mirror app, but the working app itself with the actual code base). There is a real build available, but that means letting a designer touch code, and stuff could break.

Xcode (4:36)

Mio has a Mac, but she does not have all the development tools, like Xcode. I started by helping her install that and learn the basics. I saw that she could change certain things, like images, and run it in the simulator. From that point, I also wanted her to be able to get it into other people’s hands.

Images.xcassets (6:09)

¨Let’s do some build stuff on her machine”, I thought. That was a big mistake. Provisioning profiles, uploading, Crashlytics accounts, and installing software were all rough.

Fortunately, there are tools which can accommodate that, like hosted continuous integration servers, for example. I thought I could use that to automate a build and do a release to iTunes/Crashlytics.

I went into teaching mode and explained how Xcode worked to my designer. I started with the images.xcassets (to change an icon: drop it in, give it it the same name, run it, and you will immediately see a result). I wanted to take it further.

Interface Builder and @IBDesignable (6:21)

Interface Builder is great because allows people to hook up a screen quickly and set the colors. However, it also allows you to enter strings, which are then matched in code, thus causing your app to not function properly. I love Swift and compile time checking, but I do not like Interface Builder: it does not compile time check anything, allowing you to break stuff.

Get more development news like this

I created my own components (e.g. certain buttons, selection parts, etc.). I made a MainButton, with UIControl and @IBdesignable: you can set the color, the button background, the title, select a button background color.

I want to set certain colors and titles to the defaults we have discussed as a design team. Then, if my designer wants to tweak the application, she can. For example, if the default background color is yellow, she can easily play around and change it to red if she likes. In a later version, I also added the corner radius and other aspects. Interface Builder is much simpler than diving into the code.

PaintCode (9:42)

I really like vector graphics. I do not like adding multiple .png’s, although Apple has now added app slicing, app thinning, and has made sure that iTunes Connect’s processing goes through the roof. I like PaintCode because it allows me to draw vector-like graphics using core graphics in my iPhone App (for iPhone 4, 5S, 6 Plus; Retina iPad or the Mini First; iPad Pro; no matter which device, it is pixel-perfect).

You can change the default colors, but the designer can edit and export that StyleKit - Xcode will pick it up and the entire app will be changed.

You can also draw buttons. The static function on the RecruitmentStyleKit is called (drawMainButton), and it is passed the rectangle, button color, text color, title, etc, so you can dynamically change these colors. This would be way harder with a png or an xcasset. Then, in PaintCode, we supply a button StyleKit drawing method.

The one I am currently using is called Pressme, which has the mainMenu button; the StyleKit that gets generated by PaintCode will have a function called menuButton. In the end, you will have a nice round button. If you want to change the radius, or make a diamond-like shape, the designer needs to change it only in one place (PaintCode itself), and export it.

However, changing colors is done in Interface Builder. If the designer wants to change it regularly, it might become a hassle. In that case, I would be refactoring everything and getting the colors from Interface Builder, and then moving them into my Swift code and the StyleKit itself.

Stuff on the Design Machine (14:27)

Start with Xcode and a git client. Make it simple: do not start with git command line, because it’s scary. GitHub is great, because has has a sync button, which does a push, pull, merge. It does magic, and designers love magic. After installing Xcode, get the GitHub client, and make sure they have access.

Down the rabbit hole (15:45)

Giving the designer an ability to help themselves is crucial. Make sure they know where the readme is. That way, if they ever run into trouble, they can figure out for themselves how to get out of trouble (e.g. throwing away your changes, or reverting).

However, the more 3rd party tools you add to their machine, the more complex the setup. That can get confusing. Designers will understand the need for Xcode and Git, but things get less clear with things like PaintCode.

CocoaPods and Carthage are harder to understand. Explain error messages as they come along, and walk through how to fix things.

Even harder are Crashlytics and Fastlane. Help your designer out! If you get your project running in ten minutes on the machine, without installing Xcode, and downloading from the App Store, you have a good project set up.

Design branch (18:33)

To ensure that Mio did not mangle the master branch, I created a “design branch”. I keep it in sync with master or the main development branch. After a certain feature has been delivered, I will merge everything from master or develop if I am using git flow.

As they become more proficient using git and understand the concept of branches, you will be able to explain: if you want to tweak this design for a certain new feature, you can branch that. Eventually, they will be able to use a pull request. But in the beginning, stick to the magic sync button.

Readme for break downs (20:25)

Keep the readme file up to date (when adding libraries, dependencies, new tooling). A designer can run something in the simulator, but figuring out how to get it on multiple devices without running into the whole provisioning profile mess is hard. This is my continuous integration part (not on the design machine - I do not want the designer to do a release build!).

Stuff NOT on the Design Machine (21:26)

My basic structure is: the design machine pushes to git, git calls a CI server, CI runs build tools to build everything and deliver it, the build tool uploads the built .ipa to a delivery platform, which can then be downloaded.

Tools (22:32)

As for tools I think work: GitHub/Bitbucket, work great.

Continuous integration is interesting. Bitrise, focused on iOS developments, make it simple to get a continuous integration server up and running. Continuous integration includes getting the code, building it, running tests, and then delivering it. Travis CI is a big one too, but if you are starting (and you are strapped for cash), your Mac Mini under your desk will also work (with the exception that you are getting a call from GitHub or Bitbucket - an external service needs to call a machine to push to that repository).

I tried Bitrise iO: it is free, but it times out after 600 seconds. This works if you have no dependency management, but if you add Carthage, your build times will go through the roof.

As for the build tool, you can use the built-in, delivered by Bitrise, or Fastlane.

For delivery platforms, there is iTunes Connect, Crashlytics, and appetize.io.

Fastlane (24:59)

Fastlane, by Felix Krause, really is impressive. The amount of speed for implementing new features, delivering new tools, making sure that you not only can build something but also deliver it to iTunes Connect, or do the testing, upgrading your build number, doing Git or making snapshots. It’s really a nice suite of tools that you can use. Lastly, the delivery platform, where you upload you .ipa file.

Fastlane Example (25:49)

lane :buildDebug do
	
	# Build Customer
	gym ({
		workspace: "CustomerApp.xcworkspace",
		configuration: "Debug",
		scheme: "CustomerApp",
		clean: true,				# This means 'Do Clean'. Cleans project before building (the default if not specified)
		output_directory: "./"		# Destination directory. Defaults to current directory.
	})

	# Deploy Customer
	crashlytics({
		ipa_path: './CustomerApp.ipa',
		api_token 'XXXXXXXXXXXXXXXXXXXXXXXX',
		build_secret: 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
		groups: 'customer-development',
		notifications: 'true'
	})

If I run Fastlane’s buildDebug, Gym (the build tool) will create, compile the code, create the .ipa, and deliver that .ipa to Crashlytics. In this workspace, there is a configuration called “Debug”. Make sure it is clean, and output it to the current directory. Within Crashlytics, the .ipa path is specified, and it will upload with these tokens and you can specify groups (who should be notified that there is a new build available). Getting it to run on your machine calling Fastlane buildDebug means you can quickly test if your build tool is working (and uploading it, in this case, to Crashlytics).

Upload to iTunes Connect (27:29)

lane :buildBeta do

	# Make sure we start off with a clean slate
	ensure_git_status_clean

	build_number = get_build_number(xcodeproj: "CustomerApp.xcodeproj")

	# Override plist files
	set_info_plist_value(path: './CustomerApp/Info.plist', key: 'CFBundleVersion', value: "#{build_number}")

	# Build Customer
	gym ({
		workspace: "CustomerApp.xcworkspace",
		configuration: "Release",
		scheme: "CustomerApp",
		clean: true,
		output_directory: "./"
		silent: true
	})

	deliver(
		skip_deploy: true,
		beta: true
	)

	# Reset git repo for fastlane xml files
	reset_git_repo(
		force: true
	)

	# Make sure our directory is clean, except for changes Fastlane has made
	clean_build_artifacts

end

Git status is clean, I want to set the build number, change the info P list with it is new build number, then build it. In this case I want to build the release version, which also picks up different provisioning profiles and other keychain entries. I also want to deliver it (logging into iTunes Connect). At the end, reset the Git repo, and we’re done.

$ FASTLANE BUILDBETA

If I run this, it will upload to iTunes Connect (faster than Xcode, through the command line).

Check out the Fastlane website to see how many awesome plugins it has; it can really save you a lot of time.

Connecting Fastlane to your CI (28:50)

We want to make sure Bitrise gets the code and calls Fastlane’s debug. My designer pushed something to my GitHub repository. First step is for Bitrise: you get a virtual machine with OSX running on it, you get all the different tools installed. The next step is which version of Xcode do you want (Bitrise is not updated immediately but they still have the latest GM installed).

When you start running with Bitrise, it does not come with Carthage (it does with CocoaPods), but there is bash script runner to install Carthage. If you need any other tool installed on that machine, you can run any shell script you need.

Next, I need to access GitHub (the virtual machine running with Xcode needs to get the code from GitHub); it installs SSH keys to access the repository. Then, it does a Gitclone. When you set up your Bitrise, it will ask you if you want to use GitHub/Bitbucket; if you use GitHub, it automatically creates the SSH keys, and registers it in GitHub. But you can do it manually if you have some other GitHub repository, and then it clones the repository.

Make sure that it builds and has provisions. You need to upload your provisioning profiles and your keys - that means you also have to trust this continuous integration server. You call Fastlane with the lane buildDebug. GitHub, where your SSH key is stored; Bitrise, to access your repository.

This is the hook: GitHub needs to call Bitrise and tell them that something has changed. On my continuous integration server, I can say on which branch it should build. I only want to do a build debug. For example, if there is a change on the design branch, if there is a change on master, I want to do a build release (instead of a build debug). If I push something on master, I have been testing it all over the place and it is good enough to send if off to iTunes Connect. Bitrise, if the designer breaks something, they get a notification (“this did not compile; this property was missing”), and they can fix it, and delivered it to Crashlytics.

Summary (33:49)

I started on the design machine, installed Xcode, and had the designer use the simulator, making sure everybody could test it. Then I introduced other parts not on the machine (e.g. setting up, continuous integration, build tools): this is not only very nice for the designer, but it also saves you work, doing releases to iTunes Connect and Crashlytics. Everything is fully automated - the only thing I need to do is push something to GitHub. The rest is magic.

Next Up: New Features in Realm Obj-C & Swift

General link arrow white

About the content

This talk was delivered live in November 2015 at DO iOS Conference. The video was transcribed by Realm and is published here with the permission of the conference organizers.

Robert van Loghem

Robert van Loghem has been programming since he was 13 years old in Turbo Pascal. After doing over a decade of backend development in Java and some Scala, he started developing Objective-C iOS apps in 2010, mostly for Dutch Railways (NS) and smaller companies. He is now doing 99.9% Swift at 7Scenes.

4 design patterns for a RESTless mobile integration »

close