Constraint Layout and Proguard

|

I have made an App which uses RelativeLayout and LinearLayout a lot. I wanted to convert some of these layouts to use ConstraintLayout, which in many cases simplifies a layout. Also when using LinearLayout with weights it can improve performance as well.

My App also uses Google Play Services and other libraries which increase the DEX count by a lot. Hence, I need to have multi-dex and Proguard enabled, which can complicate things a bit.

As a reader you may know, Xamarin does not provide Proguard rules which are merged with the default rules, similar to what a native Android dev might be used to from Android Studio, gradle and the ecosystem around that. So you have to add rules yourself to prevent Proguard from removing code that you are actually using.

In the case of ConstraintLayout I added the following rules in my proguard.cfg file in the app project, to have it survive Proguard’s stripping process.

# support constraint
-dontwarn android.support.constraint.**
-keep class android.support.constraint.** { *; }
-keep interface android.support.constraint.** { *; }
-keep public class android.support.constraint.R$* { *; }

These rules can be applied to other namespaces that you might find that Proguard is stripping out. Usually this will be reflected in your App, through an exception thrown at runtime telling you some class cannot be found in the Dex List.

You can read more about Proguard in the Xamarin Android documentation and how to configure it for your App.

Finding My Mac Mini On The Network

|

Often when I reboot my Mac Mini or it has been off for a long while, I find myself not being able to figure out which IP it has, when it is up and running again. I need this IP to connect to it through VNC from my Windows PC when I want to do stuff on it.

Now the Xamarin integration into Visual Studio (VS) can see the Mac. However, I really don’t want to spin up VS just to figure out the IP of my Mac. So question is… How does VS find my Mac? Easy! Using something called Bonjour. A lot of modern devices and Mac’s use Bonjour to advertise themselves on the network, along with the services they provide. In the Mac case this is often used by iTunes, AirPlay and other services to find devices to play to and from.

So by utilizing Bonjour I can find my Mac easily. For this I’ve created a little LinqPad script to help me.

I am using the Zeroconf NuGet by Oren Novotny to get a nice and easy to use client for discovering devices.

So first thing I do is to enumerate all the devices and their services on the network, which is done simply with.

private async Task<IReadOnlyList<IZeroconfHost>> EnumerateAllServicesFromAllHosts()
{
    // get all domains
    var domains = await ZeroconfResolver.BrowseDomainsAsync();

    // get all hosts
    return await ZeroconfResolver.ResolveAsync(domains.Select(g => g.Key));
}

Going through these I can simply look for a Host with the DisplayName of my Mac. Mine is called macmini-tomasz.

var services = await EnumerateAllServicesFromAllHosts();
var host = services.FirstOrDefault(s => s.DisplayName == "macmini-tomasz");

Now that I have the actual host it has a property IPAddress which I can use for my VNC client!

Voila! With these simple steps you can find your device on the network, which broadcasts using Bonjour.

Restore NuGets From Private Feed With Cake

|

I have just been wrestling with Cake, NuGet and the private feed I have for some of the stuff part of a build I am working on. When restoring stuff from private feeds with NuGet there are a couple of things you need to know about and put into consideration.

So there are basically two places where NuGet is used in Cake.

  1. When running the build script it restores NuGet packages for Tools and AddIns
  2. When you restore NuGet packages for a Solution or Project

For NuGet.exe to figure out how to contact a private feed you need to provide a configuration. It would usually look something in the lines of:

<configuration>
    <packageSources>
        <add key="PrivateRepo" value="https://some.url" />
    </packageSources>
</configuration>

For the private package sources you would additionally have a section with credentials or API keys like:

<packageSourceCredentials>
    <PrivateRepo>
        <add key="Username" value="cheesebaron" />
        <add key="ClearTextPassword" value="super_secret_passw0rd" />
    </PrivateRepo>
</packageSourceCredentials>

You can read more about the schema and each section in the official NuGet documentation for the NuGet.config.

1. Restoring NuGet packages for Tools and AddIns in Cake

So a couple of things to think about when restoring NuGets for tools and AddIns in Cake, is how you specify them.

Usually you simply add something like the following in the top of your cake script:

#tool nuget:?package=MyPackage

This will tell NuGet to look in all configured sources for MyPackage latest stable version.

You can control which source to look explicitly in by specifying the source before the ? like so:

#tool nuget:https://some.url?package=MyPackage

When you explicitly set the source, NuGet.exe will only look for packages in this source. Meaning, if your package has other dependencies, lets say it depends on System.IO.Compression from NuGet and your private repository does not contain this package or does not proxy it. NuGet will not be able to restore this dependency and fail!

As for credentials and sources specified in the nuget.config, Cake will automatically pick this up, if the nuget.config is next to your bootstrap build.ps1 file. Previously I had mine in .nuget/nuget.config and nothing seemed to work, moving it helped.

2. Restoring NuGet packages for solutions and projects

After moving the nuget.config to where the build script executes from, it seems like this is applied too for restoring packages when using the NuGetRestore tool Cake provides out of the box.

This can always be overridden by another configuration if desired, by providing NuGetRestoreSettings:

var nugetRestoreSettings = new NuGetRestoreSettings {
    ConfigFile = new FilePath("/path/to/nuget.config")
};

NuGetRestore(sln, nugetRestoreSettings);

Cake In Process NuGet Client

Now as of Cake 0.22.0 there is something called In Process NuGet Client, which you can enable by adding:

$ENV:CAKE_NUGET_USEINPROCESSCLIENT='true'

To your build.ps1 or by using the --nuget_useinprocessclient=true argument. Read more about configuring it in the Cake docs for Default Configuration Values.

All the above seems to also apply to the In Process Client.

Modifying XML nodes with Cake

|

I am using Cake everywhere I can for my builds. It is such a nice way to define your builds in a C# DSL and run them on any environment.

Recently I had the need to patch a bunch of attributes in some XML files. Of course Cake has a tool for that! This is called XmlPoke. This tool along with a little bit of XPath knowledge and you are ready to update your XML files!

Lets say you want to update your AndroidManifest.xml with the newest versions for your App. This is usually done in the root element of the manifest, funnily enough called manifest:

<manifest 
    xmlns:android="http://schemas.android.com/apk/res/android"
    package="dk.ostebaronen.cheesyapp"
    android:versionCode="1"
    android:versionName="1.2.3"

The two attributes android:versionCode and android:versionName are the ones you want to update.

So first thing needed to be done is to load the namespaces. Even if you have a namespace looking like xmlns="http://some.schema.com/" it needs to be loaded and used in the XPath. To load these XmlPoke has a XmlPokeSettings class:

var settings = new XmlPokeSettings
{
    Namespaces = new Dictionary<string, string> 
    {
        {"android", "http://schemas.android.com/apk/res/android"}
    }
};

In the case of the Android Manifest, we only have the android namespace. In the Namespaces dictionary, you would otherwise load all the namespaces that you need for your XPath queries. In the case of a naked xmlns you would also name it something, it could be called root.

With the settings in place we are ready to modify the Android Manifest with the XmlPoke alias. The XPath for the two attributes would be, /manifest/@android:versionCode and /manifest/@android:versionName. Usage in Cake would be as follows:

XmlPoke(manifestFilePath, "/manifest/@android:versionCode",
    versionCode, settings);

XmlPoke(manifestFilePath, "/manifest/@android:versionName",
    versionName, settings);

Tying all this information together in a Cake Task:

Task("Update-Android-Manifest-Version")
    .Does(() => 
{
    var versionCode = "2";
    var versionName = "1.2.4";

    var settings = new XmlPokeSettings
    {
        Namespaces = new Dictionary<string, string> 
        {
            {"android", "http://schemas.android.com/apk/res/android"}
        }
    };

    XmlPoke(manifestFilePath, "/manifest/@android:versionCode", 
        versionCode, settings);
    XmlPoke(manifestFilePath, "/manifest/@android:versionName", 
        versionName, settings);
});

For versionCode and versionName I like to use GitVersion to calculate these, but you could load these from somewhere else, or they could be arguments to your Cake script, it doesn’t really matter as long as they are strings.

Lets take a look at how this looks when you have a naked xmlns declaration. Here is what the root looks like for a Azure Service Fabric ApplicationManifest.xml file:

<ApplicationManifest 
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    ApplicationTypeName="CheesyApp"
    ApplicationTypeVersion="1.2.3"
    xmlns="http://schemas.microsoft.com/2011/01/fabric">

In this case we still need some namespace declarations:

var settings = new XmlPokeSettings
{
    Namespaces = new Dictionary<string, string> 
    {
        {"sf", "http://schemas.microsoft.com/2011/01/fabric"}
    }
};

xsi and xsd are not super important, unless you are going to query nodes using these later on. But to update the ApplicationTypeVersion we need the naked namespace.

The query in this case would look like /sf:ApplicationManifest/@ApplicationTypeVersion. These Service Fabric Application Manifests also have some ServiceManifestRef nodes with ServiceManifestVersion for each of the services you have in your app.

<ApplicationManifest ApplicationTypeVersion="1.2.3"
    xmlns="http://schemas.microsoft.com/2011/01/fabric">
    <Parameters>
        <Parameter />
        <Parameter />
        <Parameter />
    </Parameter>

    <ServiceManifestImport>
        <ServiceManifestRef ServiceManifestVersion="1.2.3">
    </ServiceManifestImport>

    <ServiceManifestImport>
        <ServiceManifestRef ServiceManifestVersion="1.2.3">
    </ServiceManifestImport>

    ...

For the scenario here with multiple attributes XPath can also help you. The query for the ServiceManifestVersion would look like //sf:ServiceManifestRef/@ServiceManifestVersion. Notice the two slashes //. In XPath this means select multiple nodes.

Hopefully this gave you a good idea about the usage of XmlPoke in Cake!

Moving The Blog To Jekyll

|

Ever since 3rd July 2012 this blog has been running on the blogger.com platform. However, I’ve grown tired of how things are managed in the blogger CMS and how blog posts are written. Especially when adding code blocks it is a huge pain. Since, this blog contains so much code and is mainly about code, I’ve been looking for a better way of writing.

Enter GitHub Pages and Jekyll! Now this blog is static, content is managed on GitHub and posts and pages are written in markdown, which I am used to with documentation for MvvmCross and issues and pull requests on GitHub. If I need to change something, I can install some of the many Jekyll plugins or just quickly change some HTML or CSS, test it locally and push the changes to GitHub, using git which I use all the time for code anyways!

This workflow suits me much better and hopefully this means more focus on writing blog posts for you to read! Also hope you like the makeover of the blog!