Build Xamarin.Forms from Source
One thing I’ve found not much information out there on is how to build your own copy of Xamarin.Forms and use it in your application. With just a little effort I was able to setup Visual Studio Team Services to build my fork of Xamarin.Forms and deploy a NuGet package to our private feed on MyGet. I think people out there are probably interested in setting this up, especially if you have a project pushing Xamarin.Forms to its limits.
So why would you do this?
- You want to fix an obscure bug that is important to you, but maybe not everyone
- You want to make something that is internal, public instead
- You want to add a new feature to Forms
These cases all might not apply to everyone, so they are not necessarily pull request worthy. It also prevents the need for you to wait for your pull request to be accepted, and it is quite a bit of work to submit a pull request… I don’t have bucket loads of free time these days.
How do I do updates?
So this brings up a concern… If you have your own fork of Xamarin.Forms to maintain, how do you get updates from upstream?
I took this approach in Github:
- Make a fork from xamarin/Xamarin.Forms to Hitcents/Xamarin.Forms
- I made a branch off of 2.2 named hitcents and made it the default branch
- I made changes to hitcents and setup my CI to build it
- Later I pulled from xamarin/2.3 to update my hitcents branch to Xamarin.Forms 2.3.x
- You *may* need some git skills to fix merge conflicts here
This effectively lets me keep up to date with the latest version of Xamarin.Forms when they ship new versions.
So how do you set it up with CI and MyGet?
Step 1) Mess with solution and csproj files. Commit here.
I found the NuGet packages relied on XML documentation for a few projects, and I found no information on how they do this. So I naively enabled XML documenation for Xamarin.Forms.Core and Xamarin.Forms.Xaml. It worked!
I also removed all WinRT or Windows Phone 8.x projects in favor of UWP. They had dependencies on Bing Maps and the Windows 8.1 SDK that I didn’t want to mess with. We only would care to use UWP going forward.
Step 2) Next I monkeyed with *.nuspec files. Commit here.
Basically I just needed to remove all the WinRT/WinPhone stuff we took out of the solution.
Step 3) Setup CI on VSTS.
So the first easy build step is to create a “Build Visual Studio Solution” step and point it at Xamarin.Forms.sln:
Setting up the NuGet package was a little trickier. I was able to figure it out by testing it command line. The key here was an $IdAppend$ variable in their nuspec file. Filling it out with ‘.Hitcents’ allowed me to effectively name our NuGet package Xamarin.Forms.Hitcents–exactly what we want.
Next I justed packaged up the NuGet package as a build artifact:
Step 4) Setup MyGet.
MyGet has direct integration with VSTS (docs here), which seemed the easiest option for me. You can also set a build step that runs ‘nuget push’ against MyGet–you may need to take this route for other CI systems.
I pointed my private MyGet feed to our build definition in VSTS, and it automatically picks up build artifacts and pushes them to the feed:
So now I have a private copy of Xamarin.Forms on MyGet. How do I use it?
The key here is to put a nuget.config file in your app’s repo:
<?xml version=”1.0″ encoding=”utf-8″?>
<!–NOTE: using v2 here for Xamarin Studio–>
<add key=”nuget.org” value=”https://www.nuget.org/api/v2/” />
<add key=”Hitcents” value=”https://www.myget.org/YOURPRIVATEMYGET/api/v2″ />
I found that with current versions of Xamarin Studio, it was best to use NuGet v2 URLs for this. In MyGet you want to use the “pre-authenticated V2 URL” under FEED DETAILS.
Then in Visual Studio, you can install your custom NuGet package directly from the IDE:
So what kinds of things did I change in our copy of Xamarin.Forms?
Once I set this up, I had ultimate freedom… to do anything I want! And my feet were looking like a nice target!
Luckily, nothing has gone wrong yet.
Here is a quick list of the stuff I’ve done:
- Make XamlLoader public (details on a future post) – commit
- Fix crash our app causes in VisualElementTacker – commit
- BindingContext does not trickle down from ListView to ListView Header/Footer – commit
- Made it possible to run Xamarin.Forms inside Unit Tests with InternalsVisibleTo (details on a future post) – commit
- Made Device.InvokeRequired public – commit
- Fixed full screen on Android when running AppCompat (it had gray line at the top of our app) – commit
- [Performance] fixed call to an odd delegate in Xaml parser – commit
- [Performance] added a naive reflection cache in Xaml parser – commit
The two performance ones I only tackled after they appeared in the Xamarin profiler in our app.