Adventures in PCL and Xamarin - a cautionary tale (and a solution)

Much to the surprise of one of my co-speakers, I've started working on my Codemania talk (which might also end up being some of the Auckland iOS Meetup talk). I wanted to try to do as pure a cross platform solution as I can, so the obvious route was to use PCLs (Portable Class Libraries) where possible.

UPDATE: More info here. You most likely don't want to act on ANYTHING in this post. Tho it might be fun to read anyway.

The idea here is to do the following:

  • A single library (BigTed.Core) which contains things which I share between various projects - ie, they are not specific to this project. This has things like TinyMessenger, TinyIOC*, Sqlite-net, and other common bits.
  • A single core library for this project (CodeMania.Core). This has all the business logic for this project.
  • An application for each platform (CodeMania.IOS, CodeMania.Android, CodeMania.Tests), which is specific to that platform.

TinyIOC (and possibly Sqlite-net) is a slight exception to this. It uses some bits which the PCL Profile doesn't allow, but Xamarin.iOS and Xamarin.Android do, so I've put a wrapper interface in the Core, and pushed the IoC container down into it.

From here down, I'm writing this as an example of how NOT to do it. Read to the end for the actual solution.

I started out with the Beta branch of Xamarin.iOS, but quickly found I was hitting some problems, so I switched over to the Alpha branch, and also tried to move some of the reference assembles over from Windows, as James Montemagno says to do here.

Before you go off and try this, stop. Don't do it. Xamarin now have an arrangement with Microsoft to ship the reference assembles, so you don't need to, and shouldn't do it. Just stick with what comes out of the box. I had to delete mono (literally) and reinstall to get it working again.

Once I had that done (again, don't do it), I tried to use Profile104, which looked like the right one. The problem is, 104 is one of the only ones which is not included.

I had already added Json.Net via NuGet at this point. More on that in a moment.

At this point, I have:

  • BigTed.Core - Profile104
  • CodeMania.Core - Profile104, Json.Net and other bits from NuGet
  • CodeMania.* - native

Suddenly, the two mobile native ones (iOS and Android) refused to talk to the Core libraries. "What the hell, this was working before?". I tried various other Profiles, but all of them failed, so I "phoned a friend".

@conceptdev @slodge OK, so can X.IOS not consume a Profile104 DLL? 'cos (alpha) XS says no.

The answer was clear:

@conceptdev: short answer: profile support matches the same set supported by VS2013… 104 isn't there :-(

OK, so I had a non-existent profile. Lovely. Just refreshing Mono wasn't going to fix this, as I'd changed and added assemblies inside /Library/Frameworks/Mono.framework so I deleted Mono and started again. This time, Stuart, who's been thru all the pain of PCL and then some, pointed out

@slodge: @fastchicken 158

(short, and to the point, as always). After reinstalling Mono, I had Profile158, so I selected that. Finally, BigTed.Core could link, but CodeMania.Core (which uses Task a lot, as well as Json.Net) couldn't! ARGH! The errors I was getting were saying that it couldn't await Task<T>, and it couldn't find System.Object, which is kind of key to everything in the .NET world.

After a bit more of a google around, I twigged on the solution.

When you install a NuGet package, it may have a number of assemblies in it. A single package might have a PCL, a specific assembly for .NET4.5, another for .NET 4.5+Sivlerlight5 etc. I had downloaded all the extra packages when I was on Profile104, which meant I had the wrong Json.Net (and others). A quick uninstall-reinstall of the NuGet packages fixed that one.

So now, my working project (source should be available after CodeMania in April) looks like this:

  • BigTed.Core: Profile158 PCL. No external dependancies.
  • CodeMania.Core: Profile158 PCL. Depends on BigTed.Core, Json.Net, Microsoft HTTP libraries (to get HttpClient), and Microsoft Async (which brings in Microsoft.BCL and Microsoft.BCL.Build)
  • The platform specific apps which depend on both of those above.

And, it builds and works! So, the learning from this:

  • Use the profiles that Xamarin provides (158 in this case). Don't go messing with the internals of the Mono framework, or be prepared to delete it and start again if you do.
  • If you are using rapidly changing alpha tools, take older blog posts (including this one) with a grain of salt.
  • If you install a NuGet package, and change profiles, reinstall it to ensure you have the right assemblies.
  • Always ask Stuart and Craig. They know things. Thanks guys.

Now to write the actual code for the talk! If you are in New Zealand, come along to Codemania, tho I think it's selling out fast...