Xamarin Forms: PCL vs. Shared Project

The first decision you need to make when creating a new Xamarin Forms project is whether the common code should be kept in a Portable Class Library (PCL) or Shared [code] Project (SP).

Coming as I was from Microsoft Universal app territory I was already predisposed towards using the Shared Project variant (that’s what Universal Apps do by default…although you can also use PCLs with them) and in my initial reading on the subject for Xamarin Forms, the official statement was “use either”; the company has no official preference. So, great, Shared Project made a lot of sense – it was what MS was doing for Universal, Xamarin was fine with it, and it seemed to offer some other practical advantages over PCL. On paper at least, these are some of the features/trade-offs for selecting PCL vs. Shared Project:

PCL

Shared Project

Full Access to .Net Framework

No

Yes

#ifdef for platform-specific code

No

Yes

Platform-specific code requires IOC

Yes

No

What does that even mean? Well, the “full access to .net” thing has to do with the fact that in order for a PCL to work it has to restrict the framework to the lowest common denominator of what’s available for the platforms you select. The more platforms, the more restrictive the PCL becomes. When you add a PCL to any standard .Net project you actually get a dialog that lets you pick which “targets” (platforms) you want to support. When you select PCL as part of a Xamarin Forms project those platforms are selected for you and include iOS, Android, Windows 8, and Windows Phone 8 (aka “Windows Phone Silverlight 8”).

So, what does that mean from a practical perspective? Well, the PCL just might not support a feature you want to use. For example, based on the targets selected for you in Xamarin Forms, you won’t have access to the standard HTTPClient library, making it a tad awkward to call web services in the way you’re probably familiar with (in the case of the HTTPClient gap there is an easily available package via NuGet that fills this in so you’re not really unable to call those services).

Ok, so what about that “#ifdef” thing for “platform-specific” code? Well, depending on what your app needs to do, you’ll be able to share upwards of 90-95% of it via Xamarin Forms. However, there are going to be cases where you need to get at something that really isn’t generic, something that’s done a little differently on each platform. That could be something relatively significant (like a custom “renderer”) or something as simple knowing the platform-specific path for local storage. In the case of the former you’re going to build a new class for each platform that needs the custom renderer and then a reference in your shared code (the specifics depend on whether that shared code is PCL or SP). In the case of the latter, it’s probably just two or three lines of code and would be a whole lot simpler to just specify the different path values in one place, ensuring the correct one is used by protecting them with an “#ifdef __ANDROID__” structure (Xamarin projects define these symbols for you). That #ifdef option isn’t available to you in a PCL because it’s compiled separately, as its own DLL, so at compile time (when the #ifdef is evaluated) it doesn’t know what platform it will be part of.

That brings us to the third item, IOC. Inversion of Control is a fancy way of describing how you’d structure your code to accept an “Interface” as a parameter for a particular function and then any object that implements that interface, even wildly differently, would be considered a valid parameter. Since a PCL can’t do the #ifdef trick you’ll probably need to rely on a form of IOC so that you can define an Interface that represents a piece of platform-specific functionality you need, then implement that Interface for each platform and at runtime reference that implementation via Xamarin’s built-in DependencyService or a more robust IOC technology of your choice (TinyIOC, Autofac and a number of others are in common use with Xamarin and can be installed via NuGet).

After all that it starts to sound like the Shared Project approach really is a lot less complicated to work with and less restrictive as well! Yup, that was my thinking and for a few months I was pretty well convinced that Shared Project was clearly the best path to follow. The problem was, the rest of the world didn’t seem to see it that way. It wasn’t that anyone flat out said I was wrong – heck, Xamarin continued to be neutral on the matter…all the while pumping out new code examples that all used PCL for shared code. Hmmmm.

So, where do I stand now, and why? Well, as you probably guessed, I’m now firmly in the PCL camp. The “why” takes a bit of explanation but the short story is this; I came to the realization that PCL just was more popular and appeared in more samples and examples. Whether it was “better” or not didn’t really enter into it – PCL was winning the popularity contest. At the same time I realized that it didn’t need to be PCL vs. Shared Project and in fact your solution could contain both types of shared code and get along just fine. With that in mind my next medium/large Xamarin project was created as a PCL project, precisely because I knew I had the “safety net” of being able to add a Shared Project if it came that and in the meantime I would explore where the practical “limits” of using PCL was.

After building out a pretty sizeable app of nearly 20 pages following an MVVM pattern I learned quite a bit (much of which will show up in subsequent posts). About PCL I learned that not once did I run into any “limits” beyond the HTTPClient thing I mentioned earlier. I did have a few of those situations where I needed slightly different values for a variable based on the platform but I found I was able to do that in the PCL, without Interfaces and IOC, through the use of a static Device class in Xamarin. It exposes a number of helpful methods that let you make decisions at runtime based on the specific platform you’re on and also gives you access to a number of platform-specific values and helpers. Parts of this even extends to your XAML markup so that based on the platform at runtime you can have different values applied in XAML. Through experimenting I quickly discovered that this approach to handling small bits platform-specific code was far better than the #ifdef approach that seemed so appealing before.

For example, in your ViewModel in the PCL you can check Device.OS against the TargetPlatform to make runtime decisions based on the OS your PCL is running under:

Now, that’s not the cleanest looking code in the world but that wasn’t the point – if you really needed something along those lines there’s a better structure you can follow using the Device.OnPlatform feature:

You see, the big problem with the #ifdef, and this was a bit sneaky, is that only the code for the currently selected target platform is “active”. What I mean by that is when you have your iOS project selected as the Startup Project, the code in the #ifdef for Android and Windows Phone is completely ignored – it’s like it’s not there at all. This seems ok, even reasonable, until you realize that this extends into applying refactoring (only active code is touched) and unit tests; a test that contains any of this type of code is nearly impossible to run properly or to mock inputs to exercise platform-specific logic. That happens at compile time based on the project type. With the PCL approach I don’t have to deal with either of these issues.

Summary

After really exercising things with a reasonably large app based on the PCL shared code model I can honestly say I’ve not run into a single issue or limitation. Along the way I learned about the use of the Device class for smaller platform-specific tweaks and the larger platform differences were usually solved through the creation of custom renderers, which would have been the same solution had I been using Shared Project. Also, while I had the option of putting common code into a Shared Project (I added one early on, “just in case”) when it was all said and done I just never needed to.

I even had reason to bundle a few shared resources into the PCL itself so they’d be available across all platforms – no problem there either.

In short, by going through the process of building out a real-world application using PCL I inadvertently debunked every PCL “limitation” I had previously called out and developed an appreciation for a few PCL advantages along the way. I also no longer felt concerned or confused when looking at the many sample apps and other blog posts that more often than not used PCL projects; I now followed that same familiar path and can more easily understand their guidance in the context of my own application.

At the end of this long journey I can confidently say to you that PCL really is the better choice, and how I’ll start new projects, but I’ll be keeping Shared Projects in the toolbox and keeping an eye out for any situation where adding it to my Solution, along with my PCL, provides a cleaner implementation approach than just the PCL alone.

 

References

Xamarin Forms Platform Tweaks

Dependency Injection (from Jonathan Yates’ excellent XF blog series)

PCL documentation on MSDN

Bookmark the permalink.

16 Responses to Xamarin Forms: PCL vs. Shared Project

  1. Alexei says:

    Thanks for sharing your experience, Ken!

  2. Pingback: Adam J Wolf: Weekly Xamarin Newsletter Issue #39 | XamGeek.com

  3. Sohel Shekha says:

    Hi, Thanks for explaining it very easily. Now, i feel much more confident about select either of them.

    But, when i was working with PCL, i had to use ipaddress and socket related classes which were not available for PCL, which made me to move back to classic Xamarin.Android and not Forms.

    • ken says:

      Hi Sohel,

      There could be situations where PCL has a limitation and that’s where you can either use injection or add a Shared Project just to handle that one area of functionality. In either case it doesn’t mean you need to move back to Xamarin Classic though; you can still use Forms whether you’re using PCL or Shared Projects (or both). Forms is really just a UI library that sits on top of Xamarin Classic so you always have that available to you anyway.

  4. devologyltd says:

    Great article – well thought out, thank you!

  5. Rika Ryu says:

    Thanks for a good article, it is helpful for making a choice. For me the reason NOT to choose SharedProject is that it gives me headache because classes defined in external libraries and used from platform-specific projects that know about my SP, when I use these in SP, they are not highlighted, “Go to definition does not work”, even though it all builds ok. Or maybe I’m doing sth wrong…

  6. Pat says:

    Great article

  7. Steven B says:

    Have you ever tried building a project to target regular Windows and a mobile OS? By that I mean like a WPF application in Windows 7 instead of Windows 10 UAP, Windows Phone, etc., which isn’t Xamarin Forms compatible? I’m looking at trying to develop PCL’s for a WPF for Windows and an Android app.

    • ken says:

      Hi Steven,

      I’ve not tried a mixed environment with WPF and Xamarin but my guess is that you’ll run into some challenges trying to find a PCL profile that will work well across all environments. This might be a case where the Shared project approach works much better.

  8. Pingback: Xamarin: Difference between Portable Class Libraries and Shared Projects - Subodh Jena

  9. Hi, Ken. Great article thank you for writing it. What is your opinion about using .NET Standard with Xamarin? It seems that this will be the next step for PCL.

    • ken says:

      Yeah, I’m watching that pretty closely; it does seem that the writing is on the wall for there to be an implementation of .Net Core that takes the place of PCL for platforms like Xamarin. Personally I’m very much looking forward to it!

  10. Manjeet Upadhye says:

    Thank you very much !! The way you explained is very good..!!!

  11. A very well explained article with clear explanations and examples. Many thanks for taking the time to produce this.

  12. Pingback: Xamarin–notes - Yann Vasseur

Leave a Reply