If you have been around software, you are probably familiar with continuous integration, or CI. The idea behind continuous integration is simple: whenever you push code, you want to know that it works and that you didn't break anything with your changes. CI software, like Jenkins or Travis CI, can listen to changes in your git repository, then, when it finds a new commit, it will automatically build the app and run your testing suite, plus so much more.
While you may not typically think of CI along with Android, this is a powerful integration with any type of software, Android is no exception! If something breaks, you know exactly when it broke, and if you have good tests, you know what went wrong.
I am not going to talk about how to set up Jenkins. There are many tutorials or services that will do this for you. I wanted to talk about how we use Jenkins, everyday, to facilitate all the services of Klinker Apps and take the headache out of building and managing apps, so that we can focus on the part of development we enjoy: the coding.
Take the headache out of building apps.
Stop trying to remember commands the commands that you have to use every day. Stop worrying about deployment. Stop waiting on builds. Stop trying to come up with a system for sharing debug builds of your app. Free yourself from the menial tasks throughout the day. Software is about consistency. Anything that is consistent is reproducible. It can, and should be, scripted. If you get that far, the next step is automation, where Jenkins shines.
As an Android developer, the primary usage of a CI system is simply to build your apps. While this isn't the most exciting usage, it is a great start and introduction into continuous integration! This will give you (and your team), a place to pull the latest
apks, or compare them with older versions.
I use this all the time for apps that Jake may be working on, that I am not helping him with. Whenever he pushes up changes, I can just wait 5 mins for them to build, then grab the
apk and install it on my phone. No hassle and no interruption in my workflow at all.
Bonus: this can be used for providing builds to product owners or members of the business team. No more worrying about creating builds just for them, point them to Jenkins and they can always be up to date. Phew.
At the beginning of 2016, I finally made the switch to using Jenkins to deploy my apps to Google Play. There is a very nice Jenkins plugin where you can give it the
apk build artifact, and it will upload and release it to the developer console for you. It does multiple APKs (if you have a fancy new wearable 2.0 app), release tracks (alpha, beta, and production), change logs, and even staged rollouts.
Admittedly, when I set this up, I thought that I was being a bit silly and petty. I mean, why shouldn't I just upload the APKs manually, like I have always done? They don't take that lone.
In the end though, I set it up, and these are, by far, my most used Jenkins jobs.
There is something really nice about being able to hit a single button and stepping away while the app gets built and deployed automatically. Most my apps don't take more than a few minutes to build, but I know some apps take a whole lot longer. When you add up all the build times, upload times, and time waiting on the Play Store, this can actually lead to a pretty significant amount of time saved. If the deploy process takes you 10 mins, that is 10 minutes saved. If you are managing multiple apps, along with multiple releases a week, like I do, this can even save a few hours a week, which is awesome!
If only APK Mirror had a third party API. I would hook that up to my deploy jobs as well. Maybe someday.
Managing Play Store Assets
To go along with distributing apps, you can also automate all of your Play Store assets. This includes descriptions, screenshots, icons, feature graphics, the whole works.
Automating assets really starts to save you time when you are managing multiple translations. If you have specific assets for each language, this takes the variability out of updating them. No need to worry about which screenshots you have uploaded or which descriptions have changed, just upload everything at once.
I don't localize very many of Klinker Apps assets, but I have used this gradle plugin for multiple clients that did localization. This made a huge difference in the release process. I had been spending an hour making sure everything was updated for each release, now I spend 10 seconds to click deploy button.
Deploying Library Artifacts
I have said it before, but Jake and I are huge into open-source work. Jenkins can be a great tool for releasing to Maven Central, or whatever host you choose.
Setting up the signing/upload to the Nexus repository can be kind of a pain. Especially when you have multiple computers or team members working on a library. We use Jenkins to release all of our library updates, so that we don't have to worry about the specific signing configurations. We loaded the release keys on to the Jenkins box, then, all of our deploys get routed through there. Again, just hit the big green button.
Basically, we just push up to GitHub, run the Jenkins job, and release the artifact. Chris Banes made an amazing gradle plugin for uploading artifacts.
Integration with Testing Suites
If you have been in an enterprise environment, you probably are familiar with how many testing suites they have, how they run them, and when they run them. Jenkins is key in automating these suites.
For Android, we do unit and integration tests through Robolectric, as well as UI integration tests with Espresso. Both of these are invaluable for an Android developer. Whenever I push up to the repo, I run both of these suites. If anything fails, I stop what I am doing and fix it.
Some people prefer not to run the integration tests with every push, which is totally fine if that is what you choose. These tests usually take longer, so you could set them up to run once a night or whenever you feel like running them. How you run these tests is up to you and how quickly you want the feedback cycle to be.
Bonus: If you really want to get fancy with these, set up your Jenkins with build lights to annoy you into fixing your failing tests!
Integration with Web Services
With our later projects, we have started to expand beyond just Android work. We have Rails and Node.JS backends, static sites, our ghost blog, plus some other random projects.
When you start to reach the point of managing so many different systems and deployment pipelines, things can get confusing quickly and you can get lost along the way. When you are doing these deployments manually, you can make mistakes and do things differently every time. This type of inconsistency can be very bad, depending on the scale of what you are doing.
Jenkins is all about automating, and, in turn, consistency! Whether you are deploying to S3, EC2, Heroku, Firebase, Digital Ocean, or any other cloud host in the market, automating these builds and deployments will vastly simplify your workflow - once it is set up once, you don't have to worry about it anymore.
Bonus: Continuous Delivery/Deployment is also a huge thing in the web right now. While it isn't really feasible for Play Store releases, it comes highly recommended for deploying your web resources, if you have a staging server or test environments. Of course, Jenkins makes it all possible.
Running Java Programs
The last item here is a bit unique to Klinker Apps. We use Jenkins for an internal project that I made, and it turned into one of the most used, and important, apps on my phone. With Jenkins, we run a simple Java program that manages push notifications to our devices, for various services. We call it PushSync.
One thing that PushSync does is open up a Twitter
UserStream that listens for mentions or any other activity on our Twitter accounts (@KlinkerApps, @TalonAndroid, @lukeklinker, @klinker41). Whenever something happens, it sends a push notification to any devices subscribed to that account. It is a really slick service, and completely custom. Unfortunately it isn't something that can ever scale, since it is just a
UserStream, and not using Twitter - restricted -
SiteStream. People always ask me how I respond so quickly: I don't use Talon Pull anymore, I set up my own personal push notification system.
PushSync started with Twitter, but we have expanded it to other services, over the years. We listen to changes on our GitHub's, as well as Facebook, before they shut down their notification RSS feed. We can really hook into any web service with this, watch for changes or updates, and tell our devices about them, immediately.
PushSync has turned into a valuable business tool for me. Running this through Jenkins allows me to watch the status wherever I am, restart it if necessary, and deploy changes, without logging into the box. If you have a long-running, small, service like this, set it up with Jenkins!
Those are just a few ideas of how we use Jenkins here at Klinker Apps. There are so many things that you can do with it, anything that can be replicated, can be scripted, and can be run through a continuous integration server.
For a few more ideas: anything with AWS can and should be scripted. Everything from manual scaling to updating the stack or baking new AMIs, even checking spot instance prices. You can automate creating screenshots or promo images for your apps or use it to ping your sites to see if they are up.
Jenkins has changed the way I code, for the better. It takes the worry out of development and deployment to let you focus on the code. I am not a devops guy, so after I figure something out once, I don't want to worry about it again.
What do you all use continuous integration for? Have any big ones that we aren't using? I would love to hear some of your ideas!