At In The Pocket, we used to be mostly focused on native development. However, we recognized the benefits of working with cross-platform frameworks: a single code base leads to a better management of feature parity and maintenance, while equally decreasing client costs.
Xamarin became open source and free for community developers in a short period after its takeover by Microsoft. These (in our view) positive changes led us to the point where we decided to investigate Xamarin as a cross-platform solution for our client’s projects.
After working for almost three years with Xamarin, we want to share our experiences and techniques with the different types of Xamarin projects we have been working on.
If we’re talking about Xamarin, we need to clarify that there are multiple approaches to using Xamarin. You can use Xamarin Native, which is the more traditional approach. With this approach, we can share the business logic of an application with other platforms, but the UI layer still needs to be created separately for each platform. The second approach is called Xamarin Forms: this builds on top of the traditional approach, but adds some abstractions to commonly used UI components. This allows us to write our UI once for several platforms.
We were quickly sold on the idea of Xamarin Forms, as it implies sharing both the business logic and the UI of an application. While shared business logic is already a big advantage, we used to spend a lot of time on creating separate views for each platform. The idea of only having to do this once was really appealing, so we decided to give Xamarin Forms a shot.
Initially, this seemed to be a good approach. As we were indeed sharing both business logic and views, there was no longer a typical Android developer and iOS developer: we were all working on the same code instead of in separate silos, which made for very tight collaboration.
However, as projects advanced, we encountered some unforeseen limitations. Firstly, at In The Pocket, we pride ourselves on delivering pixel-perfect designs. We want our projects to look perfect and perform without any hiccups. With Xamarin Forms, you can quickly create a basic-looking UI, but as soon as you want to start customizing, you need to turn to custom renderers. While our designers made compromises to make the views less complex, we still needed a custom renderer for many of our views. This way of working was slowing us down considerably, and we were creating once again separate views per platform.
Another issue was the performance: while it was acceptable on iOS, we noticed that our Android builds felt slow, especially at the startup. Also the rendering of XAML pages turned out to be a bottleneck, which caused hiccups during navigation. While we made some changes to improve the performance, in the end we were still not happy about the smoothness of the application.
I think the main issue we had with Xamarin Forms, was that it just wasn’t up to par with truly native applications. We were all native developers until we started with Xamarin, and where we used to have the means to customize virtually anything and have native performance, Xamarin Forms did limit us in both development and performance.
I’d like to note that this was the experience we had with the framework. I’m certain many other teams will find Xamarin Forms the perfect framework for their applications, and they’re probably right. For In The Pocket, Xamarin Forms wasn’t the perfect fit as we felt hampered by some of its limitations.
With our enthusiasm tempered by our struggles with Forms, we decided to create our next Xamarin projects with the Xamarin Native approach. Since we still had a healthy mix of Xamarin experienced Android and iOS developers in our team, it was no problem to switch to this approach.
Very quickly it became clear that this way of working was a better fit for our needs. While the business logic was still shared, we now had the ability to customize the UI in a more native way, like we were used to. The performance was also (nearly) the same as on native platforms, and we could still share much of the code base because of the many third-party libraries out there. These help with sharing some platform-specific logic components, such as a database or looking up device info.
Another benefit for us specifically, is that we can take advantage of the native experience that is already present in our teams. Since our views are still handled natively (albeit in a different language), we can spar with the other native developers about features and how to implement them.
In order to develop a Xamarin Native application, we did need to change the way we approached features. While we could just assign any developer to a Xamarin Forms story, we now had to expose the public properties of the viewmodel before the other platform could plug in their views. Currently, we let one platform take the lead on a feature, creating the views and viewmodels first, while letting the second platform plug in after the first platform had finished its coding, or at least its viewmodel. We found out that this approach causes the least conflicts while developing simultaneously.
Communication is key in Xamarin projects: a change in a viewmodel might have consequences in both platforms. Changes that impact the native implementations need to be documented on the stories, and we communicate it explicitly to the involved developer as well. By working closely together, we have become a better team, and better developers.
Currently, we are using MvvmCross as our framework to share business, communication and presentation logic between the platforms. This framework has been around for a while, and it has definitively proven its value over the years. It’s also very well maintained, with regular new releases, and always extending documentation. It’s built from the ground up to be extensible and adaptable. This enables us to quickly build apps on the base implementation - while allowing us full flexibility in tweaking the UI and the presentation.
Of course there are other interesting frameworks out there. We continue to keep an open mind to other frameworks, and since we like reactive programming, we probably will give ReactiveUI a go as well.
One of our Xamarin projects involved another approach to Xamarin development: working with native bindings.
All of the UI components and the UI logic were built in a native project, that was compiled to a native library. These libraries were then consumed in a Xamarin Bindings project, where we could connect the UI components to the Xamarin environment.
This allowed us to quickly upscale the team with developers that had no experience in Xamarin. For them, it was just another native project, where they could work within their competence. It was then up to the Xamarin developers to connect the libraries with the Xamarin project.
This approach also gave us a lot a freedom: we could use all native components and libraries at your disposal internally in the library, and you didn’t need to worry about binding these libraries to Xamarin, since they were not exposed to the Xamarin component.
However, this approach was not without its flaws. The connection between the native component and Xamarin component was done through abstract classes that were created in the native component. These were implemented afterwards in the Xamarin component (viewmodels for Android, controllers for iOS). This meant that we had to create separate projects, so code reuse was not feasible.
Another obstacle was the debugging of the UI components in combination with the Xamarin project. We created a mock project to quickly test all available native components and views. However, when combined with the Xamarin component, we sometimes experienced issues that weren't reproducible in the mock project. Debugging these issues proved to be very hard, as breakpoints weren't possible in the Xamarin Bindings projects and as we thus were limited to using logs.
At In The Pocket, we’ve worked with the different variants of Xamarin. While we recognize the benefits of Xamarin Forms, it’s been a bumpy road for us as it just wasn’t a good fit, due to limitations in customizability and performance issues. The Xamarin Native approach is a lot more to our liking, especially in combination with a framework like MvvmCross. It allows us to share our code base, while still being able to deliver a pixel-perfect design, with a near-native performance.