My experience dealing with Microsoft in the old Windows Phone times

This summer marks exactly a decade since I started doing mobile apps development. My first mobile app was called MyTVShows and was released to the Windows Phone Store in summer of 2011.

The app solved a practical problem for me, keeping track of new episodes. I later rewrote the app as TvTime which was one of my most successful Windows Phone apps.

My times of doing Windows Phone development are long over as the platform has been dead for many years but this reminded me of all the struggles I had to deal with when interacting with the local Microsoft branch.

Disclaimer: Microsoft is a huge company so my experience is hopefully not the general experience of everyone from those times, people on all the local branches are different.

Windows Phone app competitions

In 2012 the Czech Microsoft started a competition giving every developer a Nokia Lumia 800 for publishing 3 apps to the Windows Phone Store.

The problem was the quality of those apps did not matter at all. The goal was to increases the number of the apps as much as possible, probably reaching some arbitrary number set by Redmond.

The Czech Windows Phone Store was flooded by crappy apps created only because of this competition, not having any real value for the user. I remember an app with one input and one button doing some kind of number conversion.

Microsoft just wanted to bump the app numbers count by any means necessary to be able to compare the Windows Phone Store to other mobile app stores.

This also reminded me that Microsoft was really bad at competitions overall, another example was destroying DVLUP after purchasing Nokia.

[Read More]

Allowing parallel iOS UI tests runs in CI

If you have your CI machine set up to run multiple jobs in parallel you might have encountered a problem. You cannot run multiple iOS UI tests in the same simulator at the same time. They will fail.

The problem

Imagine this scenario. You have one CI machine that allows two or more jobs to run in parallel. You have a UI tests job set up. Two of your developers push changes to their branches at (almost) the same time. The CI machine then tries to run two UI tests at the same time in the same simulator and at least one of them fails and has to be retried.

You can of course solve this problem by not allowing parallel jobs on the CI machine, but that slows down the CI process. There is a better way.

The solution

You can create a brand new iOS simulator instance for every job, run the UI tests in this new simulator instance and then delete it when you are done. This way no matter how many iOS UI tests jobs you run in parallel they will all use a separate iOS simulator instance and not affect each other.

Creating a new iOS simulator instance

The first step is to choose a unique simulator name for each job. You can generate some random guid for example. In Gitlab CI I just use the ID of the Gitlab CI job that is stored in the ${CI_PIPELINE_ID} environment variable

First you need to create the new iOS simulator instance at the start of the CI job

xcrun simctl create ${CI_PIPELINE_ID} com.apple.CoreSimulator.SimDeviceType.iPhone-11 `xcrun simctl list runtimes | grep iOS | awk '{print $NF}'`

This command creates a new iOS simulator instance with the given name using the iPhone 11 device and the latest simulator runtime. Using the latest simulator runtime makes sure that when you update Xcode on the CI machine you do not have to do any changes to you CI scripts.

Using the new iOS simulator instance

Now that you have a new iOS simulator instance created you can use it to run your iOS UI tests. You can simply pass the name to the xcodebuild command if you use it directly or use it instead of the device type when using Fastlane

[Read More]
CI  Xcode  iOS 

Reading environment variables from iOS and macOS unit tests

In some environments like the CI/CD you might need to read environments variables from your iOS or macOS unit tests.

A typical example might be reading secrets or configuration that is CI/CD specific and you do not want to store it in source control.

In Swift you can read environment variables using the ProcessInfo.processInfo.environment dictionary, for example

let host = ProcessInfo.processInfo.environment["apiHost"] ?? "default fallback host"

The problem is this code does not just work, there is one other step you need to do first.

You need to edit your Test scheme and add every environment variable you want to read to the Environment Variables section.

You can rename the variables but for simplicity and readability you should probably keep the same names.

Swift  Xcode 

Graying out images in Cocoa

I have been working on a macOS application recently where I encountered an interesting task to grey out flags for countries that are disabled.

I first tried overlaying a semi-transparent gray view (fun fact, you cannot directly set a background for a view in Cocoa, you need to use the layer) over the flag image but it did not look very good.

Luckily there is a way to convert a NSImage to grayscale directly in Cocoa.

You first need to create a bitmap representation your NSImage

let bitmap = NSBitmapImageRep(cgImage: cgImage)

convert it to grayscale

let grayscale = bitmap.converting(to: .genericGray, renderingIntent: .default)

and then construct an NSImage from the result.

let grayImage = NSImage(size: grayscale.size)
greyImage.addRepresentation(grayscale)

Putting it all together as an NSImage extension might look like this

[Read More]
Swift  Xcode  Cocoa 

Using different Git config for personal and work projects

I use the same machines to work on both personal and work projects. I usually have to use a different Git identity for the work projects than for my personal projects.

Previously I had my personal Git identity set globally and then used local Git configs to override it in work projects. This worked just fine but it was too much work. There is a better solution.

Git config allows you to use, or better to say include, another Git config for a specific directory and all its subdirectories. I have all my projects stored in ~/Projects and subdirectories like ~/Projects/open-source and work projects in ~/Projects/CompanyName.

I created a ~/.companyName.gitconfig that overrides just the name, email and GPG signing key to match the work identity

[user]
    name = Igor Kulman
    email = igor@company.name
    signingkey = ABC

I then included this config in my main ~/.gitconfig just for the ~/Projects/CompanyName directory

[user]
	name = Igor Kulman
	email = igor@kulman.sk
    signingkey = DEF
...
[includeIf "gitdir:~/Projects/CompanyName/"]
    path = ~/.companyName.gitconfig

to achieve exactly what I needed.

To verify and quickly check which Git identity is being used in a specific Git repository you can use this simple Git alias

[alias]    
    whoami = "! git var -l | grep '^GIT_.*_IDENT'"
macOS  Xcode