tispr Engineering

Engineering Team blog

How to Create Rounded Corners on Top of the UITabBar

One day, our product owner requested the following: “I want to make our application more exciting and visually attractive, by slightly changing the design”.

Our task:“Create rounded corners over the UITabBar” goal in detail

Let’s code

The first approach: Set cornerRadius in all our the controllers of the UITabBarController:

1
view.layer.cornerRadius = 8.0

But the result was as expected: Rounded corners on top of my views as well: eror one

The second attempt: Use masks

1
2
3
4
5
    let roundedPath = UIBezierPath(roundedRect: bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
    let maskLayer = CAShapeLayer()
    maskLayer.frame = bounds
    maskLayer.path = roundedPath.CGPath
    layer.mask = maskLayer

After some research, we understood that each controller in our UITabBarController is a UINavigationController. As result, rounded corners disappear after pushing any next controller. The third try: We applied it for all main views. We created an extension of UIView and used it where it is required.

1
2
3
4
5
extension UIView {
    func makeCornerRadius(radius: CGFloat = 8, corners: UIRectCorner) {
      ...
    }
}

Cool, seems it worked! However, after testing we understood that it didn’t work with the UIScrollView, since you can see a black area while scrolling.

eror two

Finally, we decided to recalculate the mask path for UIScrollView:

1
2
3
4
5
6
public override func layoutSublayersOfLayer(layer: CALayer!) {
    super.layoutSublayersOfLayer(layer)
    if let maskLayer = layer.mask as? CAShapeLayer {
        maskLayer.path = UIBezierPath(roundedRect: layer.bounds, byRoundingCorners: UIRectCorner.BottomRight | .BottomLeft, cornerRadii: CGSize(width: 8.0, height: 8.0)).CGPath
    }
}

And yes, it worked! No bugs or issues.

Mission complete

This solution worked for us. If you have any alternatives, please leave in comments.

Running Docker in a GoCD Agent That Runs in a Docker

Setting up Continuous Delivery may be challenging. However, it is definitely worth the time and resource investment, if you want to release often, maintain a high quality of released products and have full control over the complete process. GoCD is built on a pipelines concept described in Continuous Delivery book. Docker greatly fits into the concept, because it solves the problem of packaging applications with all required dependencies and configurations into a standardized container unit. A common build pipeline will use a Dockerfile as an input, create an image and publish it to a Docker registry. A common deploy pipeline will use a Docker registry image as an input and deploy it to a proper environment when it is updated.

GoCD in its basic setup is distributed and has a Server and one or more Agents, which are running actual Jobs and Tasks. The Server can be customized by adding new plugins, or by setting up a backed-up pipeline configuration. The Agents may have different resources to run different types of jobs, i.e. separate Agents to build java and node.js projects. Same as for any other software deliverable, packaging GoCD Server and Agents into Docker containers simplifies their deployment and maintainability. One of the challenges in this setup is running your existing Docker pipelines in an Agent, which is running in a Docker container.

So, in brief, you may find this article interesting, if you:

  • use GoCD;
  • use Docker;
  • use GoCD to build Docker images;
  • run GoCD agents in a Docker.

The most important part of this setup is a Docker-in-Docker, which we use as a base image:

1
FROM jpetazzo/dind

To run a GoCD agent in a Docker, we need to run several processes in one container. For this let’s use supervisor:

1
2
3
RUN apt-get -y install supervisor
ADD supervisord.conf /etc/supervisor/conf.d/supervisord.conf
CMD ["/usr/bin/supervisord"]

The configuration file for the supervisor will contain a section per each process, including the supervisor itself:

1
2
3
4
5
6
7
8
9
10
[supervisord]
nodaemon=true

[program:docker]
priority=10
command=wrapdocker

[program:gocdagent]
priority=20
command=/bin/bash -c "/etc/init.d/go-agent start"

Some additional tweaks may be required to run your GoCD agent properly. One of them is setting GO_SERVER in your agent configuration. Let’s assume that it is available as an environment variable with the same name:

1
echo export GO_SERVER=$GO_SERVER >> /etc/default/go-agent

Another update will allow to run sudo docker without an interactive password prompt:

1
echo go ALL=NOPASSWD: /usr/bin/docker >> /etc/sudoers

And the complete GoCD command will look like this:

1
command=/bin/bash -c "echo export GO_SERVER=$GO_SERVER >> /etc/default/go-agent && echo go ALL=NOPASSWD: /usr/bin/docker >> /etc/sudoers && /etc/init.d/go-agent start"

You can check the complete Dockerfile and start playing with existing image by pulling tispr/gocd-agent-dind:

1
docker pull tispr/gocd-agent-dind

Now nothing stops you from setting up a GoCD pipeline to manage dockerized GoCD Server and GoCD Agents.

References

How to Display Build Number and Version on an iOS App Icon

How often do you face the situation where your colleagues, QA, business or marketing report issues in test builds, but they forget to mention a build number or application version? And when they ask you about it, you spend a lot of time explaining the build number and application version, and where it can be found? When you have one to two builds per month the issue is not very big, but when you have a lot of different builds per week, it becomes cumbersome.

-For instance at tispr we build on each commit and every week for internal testing, and weekly demo’s for business & marketing departments.

Let’s solve this issue, by creating a build number and app version with maximum visibility for users!

Our solution: On the application icon. You must be thinking: A new icon for each new build?! Our answer is yes, why not.

Let’s look at the how:

images Develop - it is type/name of build (if you have a different type of builds, for instance: Develop build, Business build, etc); 1.0.1 - application version; 1023 - build number


Let’s code:

Add new “Run Script” in Xcode in “Build Phase” application icon with overlay application icon with overlay

Get build number and application version from info plist in script

1
2
version=`/usr/libexec/PlistBuddy -c "Print CFBundleShortVersionString" "${INFOPLIST_FILE}"`
build=`/usr/libexec/PlistBuddy -c "Print CFBundleVersion" "${INFOPLIST_FILE}"`

Let’s imagine that we have a function with the name “addOverlayInfo” which has two parameters (name of incoming icon, name of icon that will be generated)

1
2
3
function addOverlayInfo() {
    income_icon_name=$1
    outcome_icon_name=$2

The result is something like this:

1
2
addOverlayInfo "iPhone-60@2x.png" "AppIcon60x60@2x.png"
addOverlayInfo "iPhone-60@3x.png" "AppIcon60x60@3x.png"

where iPhone-60@2x.png, iPhone-60@3x.png - the names of the current application icons While the application builds the Xcode, the icons with the names AppIcon60x60@2x.png, AppIcon60x60@3x.png will be generated, if you use Images.xcassets. So, these names are used as second parameters in our calls.

Let’s find the icon path by name of the icon:

1
income_icon_path=`find ${SRCROOT} -name $income_icon_name`

Create a path to save the generated icon:

1
outcome_icon_path="${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/${outcome_icon_name}"

And now the most important moment: Generating icons with an overlay, including the build number and application version.

Following a quick search on the internet we found that we will need these packages(imagemagick and ghostscript). Let’s install them:

1
2
brew install imagemagick
brew install ghostscript

To find the width of the incoming icon:

1
width=`identify -format %w ${income_icon_path}`

To generate the new icon with all the important information:

1
2
convert -background '#0008' -fill white -gravity center -size ${width}x60 -pointsize 20\
caption:"$TYPE_OF_BUILD $version($build)" ${income_icon_path} +swap -gravity south -composite ${outcome_icon_path}

$TYPE_OF_BUILD - The name of our build. To complete the process you might want to consider automating it by making it part of your Continuous Delivery process.

Mission completed

You can find the full script here: Code

This article was inspired by these posts:
http://habrahabr.ru/post/262667/
http://merowing.info/2013/03/overlaying-application-version-on-top-of-your-icon

Blogging With Octopress: Editorial Workflow

Octopress is an intuitive and simple blogging platform. The official documentation includes numerous examples and tutorials: http://octopress.org/docs. The purpose of this article is to give a quick reference to commands which cover some basic workflows.

The setup of Octopress is described here: http://octopress.org/docs/setup/ and will not be covered in this article.

With a basic setup of Octopress, GitHub repo will have branches:

  • source branch for source code.
  • master branch for generated HTML code.

Basic steps (including responsible participants):

  • Create a new blog post with Octopress (content producer)
  • Submit a pull request to source (content producer)
  • Review and merge pull request (content reviewer)
  • Generate HTML code from merged code and deploy to master with Octopress (automated by Continuous Integration server)

Create a new blog post

Now let’s dig into the details of Octopress and start by creating a blog post stub including title, date, categories and others:

1
2
3
$ rake new_post["Blogging with Octopress"]
mkdir -p source/_posts
Creating new post: source/_posts/2015-07-22-blogging-with-octopress.markdown

The next step is to edit generated markdown file:

1
$ vim source/_posts/2015-07-22-blogging-with-octopress.markdown

More details on editing a post can be found here: http://octopress.org/docs/blogging/.

After any update you can check what your freshly-baked post looks like:

1
$ rake preview

As soon as a new post is ready, you just commit your code and submit a pull request:

1
2
$ git add source/_posts/2015-07-22-blogging-with-octopress.markdown
$ git commit -m "New post: Blogging with Octopress"

Publish updated site

Let’s assume you have a Continuous Integration server, which generates a new HTML code for your blog on update of the source branch and deploys it to the master afterwards.

As soon as the source code is checked out by CI, you need to setup GitHub as a deployment option, generate the HTML code and deploy:

1
2
3
rake setup_github_pages["https://github.com/tispr/tispr.github.io"]
rake generate
rake deploy

Issues

Unable to deploy updated content to master

You may experience issues with doing rake deploy:

1
2
3
4
5
6
7
8
9
## Pushing generated _deploy website
To https://github.com/tispr/tispr.github.io
 ! [rejected]        master -> master (non-fast-forward)
error: failed to push some refs to 'https://github.com/tispr/tispr.github.io'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Integrate the remote changes (e.g.
hint: 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
Deploy does not work.

This may be related to the fact that the root directory of the source code and _deploy directory for generated HTML have different git repository branches set to source and master respectively. Thanks to StackOverflow a workaround was found:

1
2
3
4
cd _deploy
git pull origin master
cd ..
rake deploy

However, if you know a cleaner way to resolve this issue, please share in the comments.

Happy blogging!