Issues Faced With Kotlin During Android Development

Kotlin seems like the future of Android development. It is a new statically-typed programming language that runs on JVM, with a very refined syntax and enhanced features. There is a lot to love about it. Kotlin is interoperable with Java, which should reduce the risk of future incompatibility. The additional language features such as Function Extensions and High Order Function make it much more extensible and scalable. The code is concise with data classes, single expression function, infix and many more… enough said. Kotlin is just great!


I started working on some real apps using Kotlin that have since been published on the playstore. I have to say it was relatively smooth sailing. Nonetheless, there were some hiccups along the way that are worth sharing.

1. Method Count Increase.

Method count increase was one of the issues I was fully aware before starting with Kotlin. At the time of writing, there are an additional 7’191 methods adding to the total method count. This would add more than 10% to the 65k methods limit. Nonetheless, I didn’t worry that much as the MultiDex support is there to help to overcome this issue.

2. Using Libraries that require Annotation.

There are many cool libraries that can assist with making Android Development much more efficient. However, when switching over to Kotlin, using some of them becomes a challenge. There are two libraries which I can’t manage to use directly after switching to Kotlin, i.) Icepick and ii.) EventBus. The main reason is that the Annotation (i.e. @State and @Subscribe) is not picked up by the code. Fortunately, with EventBus, I managed to work around this by creating a composite class object using Java Code. Note that this doesn’t mean all libraries using Annotation would not work for Kotlin. I managed to use Retrofit 2.0 and Dagger 2.0 (where both use Annotation extensively) in Kotlin directly.

3. Mocking Need Open Class/Function.

By default a class and function is considered final for Kotlin. Mocking (using Mockito) requires a non-final class. So in order to have that, we have to explicitly open a class if we would like to mock it for testing. If this is not done, it would error out easily. The more tricky issue is the function. If the function is not open, there would be no error issue when running the test. Instead of intercepting the function, it would call the actual internal function, where the test would fail with NPE. Without knowing the function needs to be open, the root issue might not be easily discoverable.

4. Java to Kotlin Converter Limitation.

The Kotlin Plugin for Android Studio is just great, especially allowing to auto convert from Java to Kotlin. However, the conversion might not be ideal. e.g.


is converted to

class SimpleClass(memberVariable: Int) {

  internal var memberVariable = 0

  init {

      this.memberVariable = memberVariable



Whereby it could be as simple as

class SimpleClass(val memberVariable: Int) {}

Anyway, it’s always good to review the converted code and explore so that we don’t just have Kotlin code in Java style, without the real advantage of Kotlin.

5. Other Converter Issue.

I love writing a new function from an object, and pressing Alt-Enter to trigger the auto-function creation. If you are writing on the Java side of code, and call a Kotlin function (that you just intended to create), sorry you are out of luck. Android Studio will only auto create that function for you in the Kotlin code.

At times for experimental purposes we would also like to convert from Kotlin to Java, given that it was inter-operable with Java. This is not possible however the tools only allow you to convert from Java to Kotlin and not vice versa. Perhaps this is by design, and I could imagine it would be difficult for Java to handle conversion of more advanced Kotlin language features.

None of these issues are show stoppers. The advantage and fun of learning new things outweighs them in any case. The language features are richer and there is so much to explore. I haven’t really faced many issues from Kotlin’s language as yet. I’m sure I’ll uncover more issues, but I don’t expect them to “kill me”. Java is always there to the rescue 🙂

As with any new thing, one other challenge is finding community support. Suppose you are experimenting with new Android Features and face a road-block. If you post your question to Stackoverflow using your Kotlin code, you are unlikely to generate support.

So… you might as well be the one who supports others… which is in itself a good thing! 🙂

Respond 2016

In its third year and bigger than ever, Respond Australia’s Responsive Web Design Conference, was held for the first time in two cities, over two days. Kicking off on the 7th April at the National Maritime Museum in Darling Harbour.


Attending ‘Respond’ fuelled me with an overwhelming sense that you can never stop learning or being challenged. 

Attending a conference like Respond isn’t something I’d usually consider. As an Experience Designer, it probably comes down to an assumption that I would not understand a lot of the code rich talks and that these talks would scare me. Ironically, one of Karen McGrane’s leading themes throughout her presentation was advising us not to make assumptions about a user’s context based on any single factor. Thankfully through a stroke of luck I won tickets to Respond during Web Directions 2015, and was able to attend the conference despite my assumptions.

Greeted by new, friendly faces sharing a career and a love of coffee just like my own, I began my solo adventure into what I’d assumed would be a daunting two days that looked something like this:


Those assumptions I made were completely wrong. The topics that were spoken about were very timely and relevant, and I even found myself eager to attend code rich talks. Not so scary after all!

Throughout the conference I picked up on some common underlying themes – opening our minds, challenging industry trends and a friendly reminder to update our passwords.

Adaptive design

What is it? How should we use it? And why is it any different from Responsive Design?

The term ‘Adaptive Design’ was mentioned quite a bit, most notably by Dina Gohil and Lucinda Burtt’s presentation from Fairfax Media on the latest SMH re-design, still under betaKaren McGrane defined Adaptive Design as serving something different. The concept is used to serve content to a user based on their specific device and context.

“Adaptive and responsive solutions work together – they’re not competitors.”

Karen summarised, “Adaptive and responsive solutions work together – they’re not competitors.” Yes it is important to deliver contextual variables to users, but the device type alone shouldn’t be what changes the experience a user might see. Many other factors come into play – analytics, location, velocity and time. Above all a seamless experience should be delivered across all devices. Don’t compromise on this experience by making assumptions.


Never forget accessibility, including catering for assistive technologies. At Bilue we believe accessibility is so, so important, we’ve written about it a few times before. People are using devices to access content more than ever. It is our job to make a product accessible, and we’re not just talking bigger fonts and AAA colour passes. We’re talking, making sure screen readers will be able to clearly communicate tasks and flows to their users.

Russ Weakley really brought it home that it’s our duty to ensure our sites and our digital products are truly accessible. Reminding us that small, simple steps can have huge rippling benefits for users that need them the most.



Digital security stakes have never been higher than they are now. Rachel Simpson from the Google Chrome team reminded us all that we are only as a safe as our weakest link when it comes to tech. Ensuring our users are secure and their experience is still pleasant can be a complicated balance to reach. It goes against human capabilities to expect users to remember different login credentials for each and every online account they’ve ever created. Often users end up falling short and expose themselves to security breaches. An important point made by Simpson was to understand that as your users are stepping through a flow they are also being expected to make a number of quick decisions. It’s important to be timely and meaningful when it comes to the safety of their accounts.


Performance of your site is directly affecting your revenue. Peter Wilson considered this hard truth, stating that performance is a hot topic in the industry and so it should be. Currently it takes 15.2 seconds on average to fully load a webpage, using a fast desktop network connection. Factor in poor mobile connections, and EFS interference, you will be losing revenue fast! Get rid of the baggage and set performance as a high priority when creating your product.

Be different

A number of speakers challenged why everything is looking a bit the same online these days and motivated us all to question exactly why that is. Navigation systems, layouts and modern frameworks together are creating websites that have become clones of each other. Be inspired by things outside of the digital world, it’s up to us to change that.

Respond has left me filled with motivation to learn, be involved and stay connected. Web Directions are holding a number of great conferences over the year, check them out here: Transform, Code and Direction.

Try! Swift 2016

On Wednesday 2nd March – Friday 4th March, I attended the first Try! Swift developers conference in Tokyo, Japan. As Apple’s new programming language begins to grow and mature it is now receiving a large amount of attention throughout the developer community. This conference was a great opportunity for developers of the iOS, tvOS, watchOS and Mac OS X platforms to present on the ways they are pushing the limits of the language. It has opened up many unique discussions on the ways the language itself can be improved, some of the drawbacks that exist and most importantly the best practices that have revealed themselves already within the community.

Leaving from Terminal 2 at Sydney Airport with a conference ticket I had only received days earlier off the waiting list, I had no idea of the experience I was in for and the great people I was about to meet. I sat contently in my seat somewhat rushed, fearful, nervous yet excited for my first trip to Tokyo.

Sydney Airport

We have already begun using Swift at Bilue with many of our clients and of course on our own internal projects. As a team we have been pushing ourselves forward, learning new things and working extremely hard to bring each other up to scratch on everything that Swift introduces. I’d decided that attending the conference was a great way to extend my learning and to exchange ideas with some of the leading developers from across the world.

It turned out that Tokyo was an amazingly beautiful place that seemed to deeply align with my passions on so many different levels. On the days leading up to the conference I found time to explore a few different areas, most notably my favourite place – Omotesando. I loved the quiet atmosphere and the subtle nature that seemed to somehow augment the buildings and the cityscape. I quickly learned this to be home to some of the finest coffee that Tokyo has to offer, including Blue Bottle Aoyama which was as amazing as its San Fransisco counterpart except without the long lines and hot sun.

Cherry Blossoms

For us Swift augments our design-led approach to building inspired products. It allows us to apply the core idioms of the Swift language into writing safer, more reliable and less error-prone code. Essentially, by writing Swift we can be more certain that our software behaves exactly the way we expect it to. By taking advantage of Swift’s protocol oriented approach to application architecture we end up building products that are far more maintainable for our clients long after we’ve touched them.

At the conference located in Shibuya Mark City, I attended countless talks that were each in their own way both insightful and intriguing. On the first day Syo Ikeda presented a great talk which dived deep into the broad Swift Ecosystem. Syo outlined the most popular frameworks, libraries, resources and tools that any decent Swift developer would need to know about. We also heard Laura Savino explore the intricacies and cross-overs of learning a new language, whether it be a new programming language or a spoken language. Gwendolyn Weston quickly wowed the audience with her well received and incredibly detailed use of Pokemon as an example of Swift Type Erasure.

Blue Bottle Coffee
Tokyo Dome Baseball
Tokyo Sunset

One of the biggest highlights of my trip to Tokyo was being able to find and attend a Yomiuri Giants exhibition game played at Tokyo Dome. Despite all of the hilariously cruel difficulty I went through to get my ticket printed at the convenience store, I managed to get in. I played baseball when I was younger, and I’ve seen a game in San Fransisco, but now I know that baseball in Tokyo is like none other. Another memorable moment took place on the Tuesday evening before the conference, many of the speakers and attendees organised a visit to Roppongi Hills. At the top of the Tokyo City View we watched as the sun set over the skyline and this view was nothing short of breathtaking.

On the second day Adam Bell from Facebook asked a really great question, “When was the last time you used an app that felt surreal, or broke the laws of physics?” He presented his doubts about the plain, flat and lifeless modern iOS application and then discussed the ways prototyping can be used to implement rich, interactive and immersive animations using Swift.

Daniel Eggert explored how Swift allows developers to breathe an entirely new life into old and rigid but still tried and tested Cocoa APIs such as Core Data. Later that day Chris Eidhof similarly presented a more Swift-y approach to UITableViewControllers and demoed a really fun and unique keyboard shortcut animation technique.

Fish Market

Ridiculously early (at about 5:00am) on Thursday morning a friend and I woke up and made the trek down to the Tsukiji fish market. I’d been told that this well known fish market will be relocated really soon, so I was really glad that I took the chance to go while I could. It was a fast and intense experience with motor scooters carrying fish barrels zooming past us, it was really obvious that we had no idea where we were or what to do. Nonetheless I managed to take some really nice photos that made the early morning well worth it.

A standout talk on the final day of the conference was the excellent talk presented by Jesse Squires from Instagram on contributing to Open Source Swift. Jesse gave a really in-depth and well thought out, yet clear and simple understanding of the Swift project structure. He told us exactly how the Swift code we write in Xcode is compiled into a binary for release to the App Store. He provided a perfect guide and recommendation on contributing to the underlying Swift library at any experience level and with any skill set. Most importantly he outlined the importance of making Swift into a language that the community as a whole can enjoy and use productively.

Swift is more than a programming language. Swift is a community!

Another great talk was Ash Furrow’s overview of the Artsy approach to testing. Ash breaks down the different approaches to each of their apps based on which approach (or lack of!) they took and how it affected the team and the product itself. I really appreciated seeing Ash give this talk and outlining the balance that is required when implementing BDD (Behaviour Driven Development) or TDD (Test Driven Development) with tight deadlines and uncontrollable circumstances. He mentioned the Snapshot approach to testing, which is definitely something that I will be taking a look into and experimenting with.

Group Photo
Wine Salesmen
Chris and Phill
Lee and Phill

There is no other way to say it than this – I met so many amazing developers and people at Try! Swift that I just know I’m going to be really great friends with for the rest of my life. It underlines exactly why I chose to become a software developer, and exactly why I believe software creates opportunities that make the world a much better place to be.

A takeaway for me from the conference was that for the foreseeable future Swift is at the bleeding edge of the Apple Developer Community. And as has come to be expected, Swift is taking shape in the form of a strong, powerful and great community. There are so many developers learning Swift together right now, each and every one pushing the boundaries of the language making it a greater language to build amazing things with over time. Swift has the potential to greatly improve our development experiences at Bilue as well as to ensure that the inspired products that we create truly fulfil their purpose for the people that use them.

Daigoji Temple

We intend to continue working hard on writing Swift and will post some of our thoughts, experiences and code here as we go. Thank you to everyone who organised Try! Swift, which turned out to be an amazing conference in a beautiful city bringing together some of the smartest minds from around the world.



New Call-to-action


Accurate Apple Device Reporting in Google Analytics

For some reason Google Analytics doesn’t expose a dimension that represents which specific model of iPhone/iPad that the user is using (iPhone 4, iPhone 5, iPad Mini 2, et al). This makes it very difficult to track your mobile users’ usage by specific device type.

This article describes the technique that Bilue uses to provide a comprehensive, accurate, future-proof solution.

Possible Solutions

Firstly, let’s look at a couple of other techniques that are often considered and discuss the shortcomings of each.

Option 1. Raw values from utsname

Apple offers APIs to retrieve the raw identifier (eg. iPhone7,2). For example:

#import <sys/utsname.h>

struct utsname un;
NSString *identifier = [NSString stringWithCString:un.machine encoding:NSUTF8StringEncoding];

This identifier can then be sent to Google Analytics as a custom dimension.

However, the values returned from this API (eg. iPhone7,1) are not fit for human consumption. Business stakeholders don’t want to see reports containing these values. Not only that, it is virtually impossible to look at the values and know which specific identifiers are related to which physical devices.

This is a technically correct solution, but offers little business value.

Option 2. In-app mapping

This seems to be the most commonly chosen solution, and basically involves the app having a big lookup table that maps the raw device identifier mentioned above into something more readable (eg. iPhone 6 Plus), and then sending this translated value to Google Analytics as a custom dimension.

The big problem with this is that the lookup table is hard-coded into the app at the time the app is shipped. The lookup logic will not know what type of device it is running on for any phone that was launched after the app was released. At that point, it has two choices:

  • Send a generic value like Unknown. In this case, Google Analytics will have a whole collection of events that are all lumped in together as coming from unknown devices. Consider the case when Apple launches 3 new phones… all three phones will be reporting as the same type: Unknown.
  • Send the raw identifier iPhoneX,Y. This is a more technically correct solution in that it doesn’t lose the raw information, however, the output in the reports will continually have to be massaged because it will contain a mixture of human readable device names and raw device identifiers.

Every time new devices are launched by Apple, the only hope for correct reporting is to release a new version of the app and hope that users choose to upgrade.

This is a brittle solution.

Option 3. Screen resolution

Out of the box, Google Analytics does provide a Screen Resolution dimension that contains values like 375x667. At a high level, these values can be reverse engineered to determine roughly what type of device it was based on the following table:

  • 320×480 => iPhone 4 (and smaller)
  • 320×568 => iPhone 5
  • 375×667 => iPhone 6
  • 414×736 => iPhone 6+
  • … plus some other values for iPad

Again, this has problems in the reporting space because the translation of the resolutions to specific models is non-obvious to the casual observer. It also is very general in that you cannot differentiate between, say, the iPhone 5, 5c and 5s.

Data Mapping in Google Analytics

An oft-overlooked feature in Google Analytics is the ability to upload a mapping file that can be used to translate custom dimensions from one value to another. We can use this to our advantage to get Google Analytics to perform the mapping.

Solution Overview

Broadly speaking, the solution involves the following steps:

  • When setting up Google Analytics, a mapping file is created to map the raw identifiers (iPhone7,1) into human readable variants (iPhone 6 Plus)
  • At run-time, the phone sends up the raw device identifier (iPhone7,1)
  • Google Analytics maps that raw identifier into the human readable value
  • Run reports using the mapped human readable version value
  • Profit?

When new devices are released by Apple, the mapping info can be updated in Google Analytics without having to ship a new app.

Another awesome benefit is that Google Analytics will also apply that new mapping info to historical events, so even if you take a few days/weeks to update the mapping info after a new device is released, it will be retroactively applied.

Implementation Details

Creating Custom Dimensions in Google Analytics

We are going to create three new Custom Dimensions in Google Analytics:

  • appleDeviceModel – Contains the raw device identifier sent from the device. eg. iPhone5,3
  • formFactor – Contains a reasonably general description. eg. iPhone 5
  • formFactorDetailed – Contains a pretty exact description. eg. iPhone 5c (GSM)

To do this, click on the Admin tab at the top of Google Analytics, and navigate your way to the Custom Definitions/Custom Dimensions menu for your property. Add 3 new Session dimensions with the names outlined above.

Google Dimensions

Your dimension numbers may be different depending on how many custom dimensions you are already using. Take note of the dimension numbers; you will need them in the next step.

Creating input data

Now you need to create a file that contains the mapping info.

Important: The first row of the mapping file must contain the dimension numbers of the dimensions you just created. The first one is the key (appleDeviceModel), and the next two are the values that will be mapped (formFactor and formFactorDetailed).

For reference, our latest file looks like:

"iPhone1,1","iPhone 2","iPhone 2G"
"iPhone1,2","iPhone 3","iPhone 3G"
"iPhone2,1","iPhone 3","iPhone 3GS"
"iPhone3,1","iPhone 4","iPhone 4"
"iPhone3,2","iPhone 4","iPhone 4"
"iPhone3,3","iPhone 4","iPhone 4"
"iPhone4,1","iPhone 4","iPhone 4S"
"iPhone5,1","iPhone 5","iPhone 5"
"iPhone5,2","iPhone 5","iPhone 5 (GSM+CDMA)"
"iPhone5,3","iPhone 5","iPhone 5c (GSM)"
"iPhone5,4","iPhone 5","iPhone 5c (GSM+CDMA)"
"iPhone6,1","iPhone 5","iPhone 5s (GSM)"
"iPhone6,2","iPhone 5","iPhone 5s (GSM+CDMA)"
"iPhone7,1","iPhone 6","iPhone 6 Plus"
"iPhone7,2","iPhone 6","iPhone 6"
"iPhone8,1","iPhone 6+","iPhone 6s"
"iPhone8,2","iPhone 6+","iPhone 6s Plus"
"iPod1,1","iPod 1","iPod Touch (1 Gen)"
"iPod2,1","iPod 2","iPod Touch (2 Gen)"
"iPod3,1","iPod 3","iPod Touch (3 Gen)"
"iPod4,1","iPod 4","iPod Touch (4 Gen)"
"iPod5,1","iPod 5","iPod Touch (5 Gen)"
"iPad1,1","iPad 1","iPad"
"iPad1,2","iPad 1","iPad 3G"
"iPad2,1","iPad 2","iPad 2 (WiFi)"
"iPad2,2","iPad 2","iPad 2"
"iPad2,3","iPad 2","iPad 2 (CDMA)"
"iPad2,4","iPad 2","iPad 2"
"iPad2,5","iPad Mini","iPad Mini (WiFi)"
"iPad2,6","iPad Mini","iPad Mini"
"iPad2,7","iPad Mini","iPad Mini (GSM+CDMA)"
"iPad3,1","iPad 3","iPad 3 (WiFi)"
"iPad3,2","iPad 3","iPad 3 (GSM+CDMA)"
"iPad3,3","iPad 3","iPad 3"
"iPad3,4","iPad 4","iPad 4 (WiFi)"
"iPad3,5","iPad 4","iPad 4"
"iPad3,6","iPad 4","iPad 4 (GSM+CDMA)"
"iPad4,1","iPad Air","iPad Air (WiFi)"
"iPad4,2","iPad Air","iPad Air (Cellular)"
"iPad4,4","iPad Mini 2","iPad Mini 2 (WiFi)"
"iPad4,5","iPad Mini 2","iPad Mini 2 (Cellular)"
"iPad4,6","iPad Mini 2","iPad Mini 2"
"iPad4,7","iPad Mini 3","iPad Mini 3"
"iPad4,8","iPad Mini 3","iPad Mini 3"
"iPad4,9","iPad Mini 3","iPad Mini 3"
"iPad5,1","iPad Mini 4","iPad Mini 4 (WiFi)"
"iPad5,2","iPad Mini 4","iPad Mini 4 (LTE)"
"iPad5,3","iPad Air 2","iPad Air 2"
"iPad5,4","iPad Air 2","iPad Air 2"
"iPad6,8","iPad Pro","iPad Pro"
"AppleTV2,1","Apple TV","Apple TV 2G"
"AppleTV3,1","Apple TV","Apple TV 3"
"AppleTV3,2","Apple TV","Apple TV 3 (2013)"
"AppleTV5,3","Apple TV","Apple TV 3 (2013)"

Importing Custom File

Using the Admin/Data Import menu item for your Google Analytics property, perform the following actions:

  • Create a new Data Set
  • Choose Custom Data
  • Give it a name like Apple Device Identifier to Form Factor Mapping
  • Choose which view you want it applied to (you probably want all views)
  • Click on Next Step
  • Select appleDeviceModel as the key
  • Select formFactor and formFactorDetailed as the imported data.

Your settings should look like the following screenshot.

Google Data Import

  • Click on Save
  • Click on Finished

At this point, you’ve defined how the mapping will be performed but you haven’t loaded any data.

Choose the Managed Uploads option for your newly created data set, and upload the file containing the mapping data. Google Analytics will verify that your data matches what it expects (for example, the header rows match the custom dimension numbers, and the coloumn count is correct). You will notice that the Status field will be temporarily be set to Processing – sometimes this takes a few minutes to change to Completed.

At this stage, the import is successful and the data will start to be mapped.

Posting from App

The behaviour within the app is pretty straightforward. You just need to send the raw device identifier to Google Analytics as a custom dimension (making sure that you reference the correct number). In the example above, the appleDeviceModel dimension is 7.

#import <sys/utsname.h>

struct utsname un;
NSString *identifier = [NSString stringWithCString:un.machine encoding:NSUTF8StringEncoding];
[tracker set:[GAIFields customDimensionForIndex:7] value:identifier];


So far, the only downside with this approach is that the mapped custom dimension data is not available in the Real-Time view of Google Analytics. For us, this hasn’t been a real problem but it is worth mentioning.

And, of course, it is worth mentioning that there has to be a very real discipline of updating the mapping data in Google Analytics when Apple releases new devices. As I mentioned before, though, at least these updates can be made outside of the app release cycle.

Yow! 2015 Conference

On Thursday 10 December, once nothing more than a $10,000 credit card debt and now a Sydney-based technology startup, Atlassian raised $US462 million in a much anticipated Initial Public Offering (IPO). It goes to show that now is as good a time as ever to push forward, break down barriers and achieve something bold.

Australia is an amazing country with a thriving technology industry that is only destined to grow.

At the forefront of this technological growth are Software Developers, Engineers and Technology Architects. The impact of technology on us all is entirely at the hands of these men and women, the systems they build and the problems they solve.

Also on Thursday 10 December, Yow Australia held the Yow! 2015 Conference in Sydney. As a proud sponsor of the largest independent event for software development across Australia, Bilue attended both the Yow! 2015 Conference and Yow! CTO Summit in Melbourne and Sydney.

Attracting the sharpest developers from across the country, the conference is an opportunity to sit infront of a diverse range of experienced, innovative and influential speakers from around the world.

Unlike your off-the-shelf technical conference, Yow! is an event focused on fostering open-mindedness, practical learning and richly engaging discussions. This year’s schedule is split into three well crafted tracks on topics ranging from Cloud Infrastructure to People & Processes, Security, Mobile, Architecture & Design, Languages, Big Data and ofcourse Software Engineering. It includes an amazing line up of well known speakers who have in many ways defined their respective industries, including – Dave Thomas, Kathleen Fisher, Sam Newman and so many more.

While there’s still another entire day’s worth of sessions about to begin, I’ve already seen talks that are going to change my perspective and approach on my work as a developer for years to come.

On Thursday morning I attended Ben Tesse & Sam Ritchie’s ‘Rethinking MVC with React Native & ReactiveCocoa’ which cast quite a unique light on Functional Reactive paradigms through the lense of Javascript’s React Native framework.

I also sat front row during an eye opening, insightful talk by Mike Magruder – ‘Mobile Performance at Facebook’ that revealed the extremly extensive efforts from Facebook sacrificed in the name of Performance testing. Aaron Bedra’s ‘Adaptive Security’ introduced me to the core concepts behind system security and how adapting to change will improve our chances against malicious attackers.

One talk that stood out as a brilliant testament to the core beliefs, intentions and driving forces for us at Bilue was Dave Thomas’ talk ‘Rigor Mortis (Avoiding)’. Put simply, Dave told his audience to ‘Think Differently’ and ‘Program Differently’. He put forward the idea that language is a limiting factor to the world around us.

What we can’t express with words, we can’t comprehend and by knowing this we can reason that by keeping an open mind, learning new languages and experimenting with different ways of solving problems we can achieve a deeper level of understanding in our work.

This concept applies extremely well to software and it holds up just as strongly when applied to everything that we do. Through an open mind, through seeking new ideas and through exploring new ways of thinking we expose ourselves to experiences and solutions we would otherwise have not even thought possible.

Yow! 2015 Conference has so far been amazing and informative for all of us at Bilue who’ve attended. New, unique and exciting ways of thinking are the creative forces driving the great work we strive to do each day. As we start to process these new ideas and perspectives from the sessions we’ve attended we’ll spend some time writing them down and sharing them with you. If you too attended Yow! 2015 Conference, enjoy today’s sessions and remember to program differently.

The State of iOS Dependency Management

Dependency management is a tricky problem to solve, even more so on iOS projects where we have to concern ourselves with things like code signing, embedded binaries, and so on. In recent years, a couple of solutions to this problem have presented themselves, each with different approaches and guiding philosophies, and each with their own tradeoffs to consider.

Manual Integration

There’s a lot of ways to integrate third party dependencies without using third-party tools. Most OSS projects use Git for source code management these days, so we can include those dependencies using Git submodules. Failing that, we can simply download the latest snapshot of a project and copy it into our project’s source tree.

With some basic knowledge of setting up Xcode projects, this solution actually gets us pretty far. It’s not the simplest or easiest approach, but it has its advantages. For one, not relying on third-party tools mean other team members can easily build your project without installing additional tools. This method is also the most resistant to breaking changes introduced in newer versions of Xcode, as there’s no waiting on a third-party to update their tools.

However we quickly run into issues as we add more dependencies to our project, especially when those themselves also have dependencies. Eventually we’re going to run into a case where two dependencies require two different versions of a library, and at that point we have to do a lot of messy manual resolution. Take the following example:


Here we have a project that uses ReactiveCocoa and the (somewhat less well-known) ReactiveCocoaLayout library. In this situation, both our project and ReactiveCocoaLayout depend on different versions of ReactiveCocoa, so in a manually integrated project we have to do the hard work of resolving this conflict ourselves.

Beause of this, and various other problems, a new solution soon arrived.


CocoaPods is a Ruby gem that handles the task of resolving dependencies for us, generating an Xcode project that builds those dependencies, and generating an Xcode workspace that lets us integrate them into our project. To include a dependency through CocoaPods, someone has to write a Podspec that describes how to build the framework, and what other dependencies it has. CocoaPods keeps a public repository of these Podspecs for open-source frameworks, and you can specify your own sources for private Pods.

If we wanted to recreate our example from the previous section, we’d create a Podfile in the root of our project with the following contents and then run pod install:

source ''

platform :ios, '8.0'

pod 'ReactiveCocoa'
pod 'ReactiveCocoaLayout'

This approach is very much inspired by tools like RubyGems, and it has a lot of advantages. For one, it makes integrating dependencies extremely easy by taking over the duty of configuring your Xcode project for you. It also aids in discoverability, with providing a searchable repository of open-source pods, and publishing easily searchable documentation.

It’s also widely adopted, with most frameworks offering official Podspecs, and those that don’t often having community-maintained specs that are kept relatively up to date. This popularity also means that when you do run into issues with CocoaPods, you’re rarely the first to and there’s likely StackOverflow answers already out there to solve your problem.

For authors of libraries, it can also reduce the maintainence burden of updating projects to build on new versions of Xcode, as CocoaPods handles the entire build process and updates whenever new Xcode versions are released. This does however mean that projects which also want to build without CocoaPods need to specify build steps in multiple places.

However, CocoaPods’ ease of use comes at the cost of quite a bit of complexity and a certain loss of flexibility in how you set up your project. For more experienced developers that feel they know how best to set up an Xcode project, the way CocoaPods wrests that control away from you can be frustrating. For library authors, it can also seem redundant to have to create a Podspec that mostly just reiterates information that’s already contained in Git and Xcode.

Finally, CocoaPods was initially designed to build static libraries and for a long time lacked any sort of support for frameworks. Initially, this was something only OS X developers really cared about as iOS didn’t have framework support prior to iOS 8. However, with iOS 8, not only were frameworks supported, but they became a requirement for using Apple’s new Swift programming language. Despite framework support eventually coming to CocoaPods, it has always felt like something of a second-class citizen.

So along came another solution.


Carthage is described by its creators as “ruthlessly simple dependency management.” Its aim is to act as a simple coordinator between Git and Xcode, that picks compatible versions of dependencies, checks those dependencies out with Git, and then builds frameworks with Xcode.

To recreate our example project with the ‘standard’ Carthage setup, we would create a Cartfile at the root of our project with the following contents and then run carthage bootstrap:

github "ReactiveCocoa/ReactiveCocoaLayout"
github "ReactiveCocoa/ReactiveCocoa"

This would pull down our dependencies and build them as frameworks, but we would still need to manually integrate them. To do this we’d simply add references to them in our Xcode project and add them to the linked frameworks section of our target’s build settings.

Compared to CocoaPods, it’s a much simpler tool, though perhaps not as easy to use. Carthage does not integrate dependencies into your project in the same way CocoaPods does, instead leaving that task up to the developer. The upside of this is increased flexibility in how you integrate dependencies: whether by embedding the built frameworks, or by creating a workspace that includes all the cloned Xcode projects of your dependencies. In fact, Carthage can add all your dependencies as Git submodules, removing the need for other devs to install Carthage at all.

For library authors, supporting Carthage couldn’t be easier. You simply need to make an Xcode project that can build your framework, and then share the build schemes contained in that project. Compared to CocoaPods’ spec-based approach, this is refreshingly simple. There’s no need to submit a spec to any sort of central repository, instead users simply refer to a GitHub repo or Git URL in their Cartfile. This decentralised approach also simplifies the use of private frameworks and forks.

Carthage also tends to speed up builds in a few key ways. Firstly, frameworks are built once when you bootstrap or update your project, and then simply embedded on subsequent builds. Secondly, Carthage integrates with GitHub’s Realeases feature to download precompiled frameworks wherever possible.

Compared to CocoaPods, Carthage doesn’t have quite as much traction. There’s still the occasional project out there that doesn’t expose any shared build schemes, but this is usually simple to resolve with a quick pull request. Carthage also doesn’t help with discovering new libraries to use, your best bet there is to search GitHub.

Swift Package Manager

Announced as part of Swift going open-source, the Swift Package Manager, or swiftpm, marks the first time we’ve had something akin to an official dependency manager. It’s perhaps a little soon to say too much about swiftpm, it’s still very early and not officially released, but the current implementation and the package manager community proposal provide a lot of food for thought.

With swiftpm, developers create a Package.swift file in the root of their project that describes their project and its dependencies. swiftpm then resolves those dependencies based on git tags, pulls them down, and builds them as static libraries.

The Swift Package Manager is similar in certain aspects to both Carthage and CocoaPods. Like Carthage, it uses a decentralised approach to dependency resolution, and builds those dependencies as standalone binaries. Like CocoaPods, it uses specification files to define libraries and their dependencies — though this perhaps makes more sense for swiftpm, as it has to run on platforms where Xcode and by extension xcodebuild don’t exist.

As swiftpm builds static libraries as opposed to frameworks, there’s currently no way to include resources like XIBs or image files in a library. However, this is highlighted by the fairly in-depth package manager community proposal as something to add in future releases, alongside numerous other features that would make it more feasible for iOS projects.

In fact, looking at the proposals set forth in that document, it seems clear that the Swift Package Manager will eventually become the de-facto solution for dependency management on iOS projects. Just not today.

Which One Should You Use?

As with most things, the answer is ‘it depends’. If you want to easily bootstrap a new project, CocoaPods will take care of most of the work for you. If you want more flexibility in how you set up your project, or you want to more easily use private libraries that aren’t in a central repo, Carthage is probably the better option.

SVG Animations – Seriously Very Good

Imagine the entire web was just static. Filled in by nothing but words, information and meaningless black and white text. We would all spend a lot less time using the internet.

Thankfully we don’t. Instead the internet is a vibrant and expressive place where we immerse ourselves each day in an endless variety of unique experiences. Animation and movement are the visual language through which we catch our audience’s attention. We apply the finesse to our words and breathe life and meaning into our work.

Scalable Vector Graphics (SVGs) are a fantastic tool for every seasoned animator. Unlike traditional image formats they are built using vector paths that save into workable, writeable code. Their output is a complex XML-based structure consisting of tags like <path>, <circle>, <rect> and so forth. To these you can assign properties and masterfully take control of your SVG graphics.

SVGs are vector paths so they scale consistently without any nasty pixelation. They can be assigned fill colours, stroke colours and even border styles. Animating them is easy using CSS3 or SMIL (Synchronised Multimedia Integration Language) and brings movement and life to an otherwise static and lifeless shape.

Here’s one I prepared earlier to highlight the possibilities that can be achieved simply through the use of SVGs and animation. It is built entirely in HTML5/CSS3 using vector shapes from Vecteezy, which I then edited and exported using Sketch.

Note: Can’t be viewed in Firefox because the browser doesn’t provide support for some of this cool stuff and the playground just ends up looking weird 🙁

  1. Outlines
    An SVG’s stroke is the border of its shape. The stroke can have multiple properties such as weight and colour. Create a tracing effect using the dashed feature of a stroke and the dash-array, dash-offset properties. These indicate length of dash and dash starting point along the edge.The trick is instead of having many short dashes, we make the stroke-dasharray value longer than the border of the shape. Then we animate the stroke-dashoffset from the stroke-dasharray value down to 0. The longer the border of the path, the higher the initial values of stroke-dasharray and stroke-dashoffset needed.ferriswheel

    <span class="s4"><span class="s4">path {
     <span class="Apple-converted-space">    </span>stroke-dasharray: 3000;
     <span class="Apple-converted-space">    </span>stroke-dashoffset: 3000;
     <span class="Apple-converted-space">    </span>animation-name: draw;
    </span></span>@keyframes draw {
     <span class="Apple-converted-space">    </span>to {
     <span class="Apple-converted-space">        </span>stroke-dashoffset: 0;
     <span class="Apple-converted-space">    </span>}
  2. Fill
    Each path can be filled with colour – this feature being a major attractor to using the SVG format. Fill can be given an opacity between 0 (transparent) and 1 (opaque). This allows us to animate from no-fill to fill.swingsNote: Elements which overlap one another (eg. the axis on the carousel above) don’t want the lines of any paths behind. To avoid this all elements first get filled in with the document’s background colour and only after with a solid colour. This is achieved by chaining three animations together.

    <span class="s4">animation-name: draw, fillBackground, fill;

    As for the colour randomness on the page: this is a little Sass mixing I built myself. It takes an input colour and returns a set of random colours within a certain range. You can check out Sass Colour Range on Github.

  3. Timing
    Originally when I built the playground, each section was dealt with individually – building it and then filling it in. Different sections were shown using Javascript’s timeout, changing the display property of each element from none, triggering the animation to start. The end result was messy so I instead used CSS’s animation-delay property to trigger specific start times for each animation. I then created an ‘end’ variable used to trigger the fill for every part of the playground simultaneously.

    <span class="s4"><span class="s4">$end-fill: 10s;
     <span class="Apple-converted-space">    </span>animation-name: draw, fill;
     <span class="Apple-converted-space">    </span>animation-delay: 0s, $end-fill;
     <span class="Apple-converted-space">    </span>animation-name: draw, fill;
     <span class="Apple-converted-space">    </span>animation-delay: 4s, $end-fill;

    Each animation can also have a timing function applied to it, changing the rate of change throughout its duration. Most elements are animating with a linear timing in order to create a more uniform and monotonous look. However certain elements have subtle changes.

    One such is the swing, which uses an ease-in-out function to make the swing seem like it’s hovering at the peak of each swing before gradually speeding towards the trough.

    <span class="s4">animation-timing-function: ease-in-out;</span>
  4. Rotation
    There is lots of rotation going on in the playground, each to varying degrees. The carousel and each carriage rotates a full 360°. The seesaw and swings move slightly less. Rotation of the swings is limited to the X-Axis so that it appears to swing back and forth rather than in a circle. Because the swings are drawn hanging down whereas their rotation moves from -33° to 33°, an animation has been included to first pull the swing back. This animation is called only once using animation-iteration-count, while the swinging motion is on an infinite loop.

    <span class="s4">animation-name: swingback, swing;</span>
    <span class="s4">animation-iteration-count: 1, infinite;
    animation-delay: 0s, 1.1s; </span>
  5. Bouncing
    There are two parts to the bouncing ducks – the spring and the duck itself. While it looks like a simple up and down motion, these two parts are distinctly different. The spring has to collapse into itself while the duck stays the same shape and doesn’t scale. Therefore the spring has its own animation using scale-Y, but the duck itself uses translate-Y to move up and down. A minor annoyance – scale and translate use different methods of determining distance (translate calculates by pixels, scale by a part of 1).ducks

    <span class="s4"><span class="s4">@keyframes spring {
     <span class="Apple-converted-space">    </span>from
     <span class="Apple-converted-space">    </span>{
     <span class="Apple-converted-space">        </span>transform: scaleY(1);
     <span class="Apple-converted-space">    </span>}
     <span class="Apple-converted-space">    </span>to
     <span class="Apple-converted-space">    </span>{
     <span class="Apple-converted-space">        </span>transform: scaleY(0.8);
     <span class="Apple-converted-space">    </span>}
    </span></span>@keyframes duck {
     <span class="Apple-converted-space">    </span>from
     <span class="Apple-converted-space">    </span>{
     <span class="Apple-converted-space">        </span>transform: translateY(0);
     <span class="Apple-converted-space">    </span>}
     <span class="Apple-converted-space">    </span>to
     <span class="Apple-converted-space">    </span>{
     <span class="Apple-converted-space">        </span>transform: translateY(10px);
     <span class="Apple-converted-space">    </span>}
  6. Sliding
    CSS doesn’t have a great deal of support for motion paths – this is still an experimental property in Chrome only. Instead of using CSS to achieve the motion of the ball sliding down the slide, I’ve used SMIL’s animationMotion property as a child node of the circle path. Path of motion is determined using the path attribute on animateMotion.

    <span class="s4">&lt;animateMotion
        path="M197.125,297.636719 C197.125,297.636719 319.5625,276.726563 385.351562,333.406251 C451.140625,390.08594 452.066406,558.484368 502.964844,571.152331 C553.863281,583.820293 634.578125,567.597656 677.324219,479.175775"
        dur="2s" begin="16s" repeatCount="indefinite"
        calcMode="spline" keyTimes="0;1"
        keySplines="0.755, 0.05, 0.855, 0.8"/&gt;

    Much like CSS animations, SMIL’s animateMotion takes specifications for animation-duration(dur), animation-delay (begin), and animation-iteration-count (repeatCount).

    In order to create an animation-timing-function three properties are needed – calcMode, keyTimes and keySplines. ‘Spline’ is the SMIL keyword to indicate a custom bezier which is then defined in keySplines. The keyTimes attribute is also required to determine the duration of the function. This timing function creates the slow-to-fast sliding motion as the ball slips down the slide.


    Both CSS and SMIL animations don’t allow for a delay between repeats of an animation. Therefore preventing the ball sliding continuously down the slide without a break requires an additional CSS animation. This animation runs for 5x the length of the ball rolling animation, and then shows the ball for 20% of that time. With a 2-second animation on the ball there is then an 8 second gap before the ball is shown rolling again. The ball is actually continually rolling the entire time, just not visibly to the viewer.

    <span class="s2">.ball {
     <span class="Apple-converted-space">    </span>animation: slideHide 10s linear infinite;
     @keyframes slideHide {
     <span class="Apple-converted-space">    </span>1%, 20% {
     <span class="Apple-converted-space">        </span>opacity: 1;
     <span class="Apple-converted-space">    </span>}
     <span class="Apple-converted-space">    </span>21%, 100% {
     <span class="Apple-converted-space">        </span>opacity: 0;
     <span class="Apple-converted-space">    </span>}

CSS and SVGs are amazingly cool and incredibly powerful. With an underwhelmingly few lines of code you can break away from the cold, lifeless and even Orwellian nightmare of a motionless information super highway.

Despite these techniques being capable of producing drastically complex animations they’re also a fantastic way to apply polish to the tiniest of details throughout your work. You can sweat the details, without sweating the details and build an experience that your users will absolutely love to use. Look out for more of these neat little animations throughout our blog posts and across our website!

Bilue’s Swift Style Guide



Today we’re open-sourcing our internal Swift style guide. This is something we’ve been working on in an attempt to codify best practices and improve codebase consistency within the company, and it’s something we’d love to have the Swift community’s feedback on.

The guide is a work in progress that’s intended to evolve as we undertake more and more Swift projects. We’re still in the early days of Swift development, and what constitutes ‘idiomatic Swift’ is still in a state of flux. As both we at Bilue and the community at large decide on new best practices in Swift development, we want to keep our guide up to date with those decisions.

Why have a swift style guide?

As the number of people working on a codebase increases, you’re more and more likely to encounter developers with differing opinions on how to write code. This can be about anything from tabs vs. spaces to things like when it’s appropriate to use computed properties.

These differences in opinion can lead to long, drawn out debates over aesthetics during code reviews. Even once a consensus is reached, it’s rarely enforced across the codebase. This approach also means the same decisions have to be made for every new project, and there’s very little consistency between the projects themselves.

With a style guide, these decisions can be made once, recorded in a central repository, and then referred to by all of the projects within our company. When a debate over style comes up during a code review, developers can simply refer back to the style guide. If a developer needs to move from one project to another, they can be assured that they won’t have to learn a whole host of new conventions and habits.

By codifying best practices in this way we improve consistency, reduce debate, and raise the general quality of all of our codebases.

How we built our style guide

Rather than start our guide from scratch, we’ve decided to fork GitHub’s style guide and modify it for our own use. This has saved us a great deal of groundwork and GitHub’s guide makes for a great starting point. We’ve made some minor changes to the original content of that guide, but so far most of our changes have been additive.

Our guide is broken up into a series of guidelines, each with a brief summary, a more detailed example to show how that pattern would be implemented, and a rationale that explains the reasoning behind that guideline. These guidelines are intended to encompass patterns that can be applied across any codebase to improve the clarity and decrease the likelihood of programmer errors.

New guidelines are added by opening a pull request on our core repo, and we generally spend some time refining new guidelines either in PR comments, or through discussion in our #swift Slack channel.

Our Swift style guide is still in its early days, but already it has sparked a lot of valuable discussion within our company. It has started pushing us towards a more consistent, company-wide coding style that makes it easier to move between projects, and is raising the baseline level of quality across each of our codebases.

If you’re looking to implement a style guide at your own company, or within an open-source organisation, our guide is under a liberal Creative Commons license and we’re accepting contributions.

Directions of the web


Don’t settle for what exists, care enough to push the envelope and design the best solution possible.

Technology and the web are incredibly exciting and yet still so new. Compared to other industries such as banking, mining or automotive it is still in its infancy, and people are doing amazing work to shape it and explore how far it can be stretched. Being so young allows us to try new approaches, make mistakes and discover new design processes and development practices that will help improve what we build.

Events such as Web Directions 2015 help the industry grow by bringing its leaders together to impart their wisdom. After two days, I felt like my head was ready to explode from excitement, learning and ridiculously excessive amounts of coffee. Web Directions challenged my existing development processes, reinforced my inner values and exposed me to a few excitingly new perspectives of thinking.


Cap Watkins, VP of Design at Buzzfeed delivered the conference opening keynote, emphasising a need for developers and designers to work closer than ever before. He introduced us to processes at Buzzfeed whereby designers and developers sit down monthly to work through minor styling bug fixes that would otherwise be de-prioritised. Designers were encouraged to be involved, learn CSS and make contributions to a codebase instead of relying on developers to make these less important changes.

I find Cap’s attitude inspiring. In my own experience I’ve found that collaboration among teams directly leads to an increase in quality.

Developers should also be expanding the breadth of their knowledge. Courtney Hemphill addressed these ideas in her talk on animation algorithms. She encouraged exploring the ways tweaking easing functions adds entirely new dimensions to a design – beyond what a designer would typically achieve.

Addressing these visual animation problems through code and logic we can further integrate design thinking into our process. By integrating knowledge from other disciplines, as developers we become more than just ‘code monkeys’. Instead, we can create fun, exhilarating web experiences. Who doesn’t want to do that?


This year’s code track was a flurry of everything that is cooler than whatever it is you’re currently doing. Programming can sometimes feel like you’re just writing the same lines of CSS over and over again – but the engineering speakers inspired developers to experiment with new methods, libraries and properties – each wielding their own success stories from real world projects.

With the uptake of the Angular and React frameworks as well as modules with ES6, there’s been a shift towards component-based development. Functionally, components have a local scope so that they don’t interfere with one another. This isn’t true for CSS. Mark Dalgleish and Glen Maddern introduced their solution – CSS Modules. This framework uses Webpack to create locally-scoped CSS classes that only apply to the component where they’re referenced. The result is cleaner, modular CSS files and reusable base classes both of which I will be keen to embrace.

Under-used features of CSS were also discussed by several in relation to enhancing web experiences. Tools such as vw, vh, calc(), rems and ems allow us to create better responsive websites. Utilising these properties will allow us to simplify our code and bring processing from Javascript into CSS. The result is fast-running websites which are more accessible and provide a better experience for the user.


An underlying theme of many talks was about how creatives need to think more about the impact of what they’re building. To deeply explore the needs of user groups that are not normally considered. An example – Government. Tom Loosemore talked through rebuilding to create a less frustrating online experience. He presented solutions to combine data from multiple sources, removing the need for users to re-enter information already stored away somewhere in a database. Reconceptualising user behaviour addressed key issues in new ways, an approach which extends beyond government.

Developers, on the other hand, simply don’t care enough about the products we’re building. The internet is obese, and we’re all too lazy to fix the problem. Maciej Ceglowski’s challenge is to build websites smaller than Russian literature (which is usually fairly small). Remove the oversized videos, uncompressed images, unnecessarily heavy ads – they’re all just bloat. We’re all guilty of ignoring the implications of page load times and need to be thinking more consciously. Give the user critical content first – then stop. Does my user care? No? Then why include it?

Go back to the basics, simplify size, simplify quantity and create a more usable web.

Be Better

Web Directions was a call-to-arms. The web is fresh, it’s pliable and we can still shape it. I’ve been playing with plenty of ideas I’ve learned, I intend to keep learning and experimenting with new technologies, new theories and improving my code in the process. Yes, there will always be more to do, but adopting an integrated approach to thinking, improving code and caring about what we build and who we build for will create an enjoyable, exciting internet for people to enjoy. I’m excited to see what direction the industry will take as it continues to grow.

For some more information and thoughts about the conference, read Amy Balsdon’s Takeaways from Web Directions 2015.

Configuring watchOS 2 Targets


To save people some headaches in the future when they have to work on watchOS 2 projects, here’s exactly how you need to configure watch targets to avoid the dreaded LaunchServicesError error 0.

App Groups
You’ll need to create a new App Group so that your watch extension can communicate with the base app. You can name this group whatever you want, but the ID should be your base app’s bundle ID prefixed with .group. So for an app with the bundle ID of the group ID should be

App IDs
This is the part that caused me the most headaches. The ID of an embedded bundle on iOS must be prefixed with the bundle ID of their parent bundle. What makes this confusing in watchOS 2 is the way the directory structure of the bundle has changed. In watchOS 1, both your watch app and watch extension bundles would be embedded directly into the main app bundle. However in watchOS 2, the watch extension is now embedded inside the watch app, which in turn is embedded in the main app bundle.
So following Apple’s rules around embedded bundles’ IDs, that means our watch app’s bundle ID should be prefixed with the main app’s bundle ID, and the watch extension’s bundle ID should be prefixed with the watch app’s bundle ID. What this looks like in practice is as follows:

  • Main App —
  • Watch App —
  • Watch Extension —

All of these app IDs must have the App Groups capability enabled, with the group configured to be the one we set up earlier.

Provisioning Profiles
These are pretty easy, just create provisioning profiles for each of the 3 app IDs we’ve created. To run your app on a real watch, you’ll need to include both the watch itself and the paired iPhone in all three of these provisioning profiles.

Xcode Targets
The watch extension and watch app should be built with the profiles and app IDs we set up for them. On top of that, there’s a whole bunch of things that can go wrong in your target configuration that’ll generate unhelpful errors. Here’s some things to check if that happens:

  • The version numbers and build numbers of the main app, watch app, and watch extension must all be identical.
  • In the watch extension’s Info.plist file, the value of NSExtensionNSExtensionAttributesWKAppBundleIdentifier must match the CFBundleIdentifier of the watch app.
  • In the watch app’s Info.plist the value of WKCompanionAppBundleIdentifier must match your main app’s CFBundleIdentifier.

Contact Info

Level 1 6 Bridge Street, Sydney, NSW, 2000

Level 1 520 Bourke Street, Melbourne, VIC, 3000

Copyright 2018 Bilue Pty Ltd ©  All Rights Reserved