Removing unused language resources from an Android APK when developing with Xamarin

If you're developing an Android app and add the Google Play Services or Android Support Library to you're app, you're probably suddenly seeing an enormous increase in supported languages when uploading the app to Google Play.
This happens, because those libraries ship with built-in multi language support and Google Play has no way of knowing that those additional language files aren't coming from your app itself.

If you're developing with Java and Gradle, the solution is simple, just add this to your build.gradle file:

defaultConfig {
  minSdkVersion 15
  targetSdkVersion 22
  versionCode 75
  versionName "1.0.0"

  resConfigs "en", "de" <--
}

This way only German and English resources are included in your final APK.

If you're developing with Xamarin for Android, you're out of luck, there isn't a built-in way to do this.
Fortunately, after some research, I've found a semi-manual solution that I've also posted on StackOverflow

  1. Download Apktool from https://ibotpeaches.github.io/Apktool/
  2. Create your final .apk with Xamarin and decompile it with apktool d MyApp.apk
  3. Go into the MyApp directory that Apktool has created and look for the res directory
  4. Remove all values directories that end with a language identifier that you don't need, e.g if your app only supports the German language, remove values-fr, values-es, etc..., but not values-de. Don't remove non-language directories, e.g values-v11!
  5. Recompile your app with apktool b MyApp
  6. The recompiled app package is now in MyApp/dist/MyApp.apk. Take this file and sign it with the signtool, then zipalign it. 7. Upload the apk to Google Play

I'm sure there is a way to automate this with a script, but I haven't yet created one yet.

Open Sourcing Espera for Android

Today I'm open sourcing one of my few closed source projects: Espera for Android

Espera for Android is the Android remote control for the already open source Espera media player.

The reason for open sourcing it is simple: It didn't make me any money (read: $0)

There is no point in keeping an application that doesn't have a viable business model closed source, so I'm opening it up for public contributions and in the next few days, I'm even making the existing premium features free.

Espera for Android is written with Xamarin for Android, Reactive Extensions, ReactiveUI and Akavache, so I hope it helps people who want to learn writing apps with these libraries.

Please note that this is my first Xamarin/Android application, so it may or may not follow the best practices of the Android platform.

Matching pairs in two observable sequences

For one of my projects that makes heavy use of Reactive Extensions, I needed to pair equal values in two observable sequences.

An example:

var sequence1 = new[]{3, 1, 4, 2}.ToObservable();
var sequence2 = new[]{1, 2, 3, 4}.ToObservable();

var result = sequence1.MatchPair(sequence2).Subscribe(x => Console.WriteLine("{0} {1}", x.Left, x.Right));

This should print

1 1
3 3
2 2
4 4

The distinction between the left and right element must be made, as I want this to work on any class and base the equality on a key selector.

My end result looked was this (you can also find this code here):

public static IObservable<Pair<T>> MatchPair<T, TKey>(this IObservable<T> left, IObservable<T> right, Func<T, TKey> keySelector)
{
    return Observable.Create<Pair<T>>(o =>
    {
        var leftCache = new List<T>();
        var rightCache = new List<T>();
        var gate = new object();
        var disposable = new CompositeDisposable();
        bool leftDone = false;
        bool rightDone = false;

        left.Subscribe(l =>
        {
            lock (gate)
            {
                // Look for the last element, as we want FIFO
                int lastIndex = rightCache.FindLastIndex(x => EqualityComparer<TKey>.Default.Equals(keySelector(x), keySelector(l)));

                if (lastIndex > -1)
                {
                    T element = rightCache[lastIndex];
                    rightCache.RemoveAt(lastIndex);

                    o.OnNext(new Pair<T>(l, element));
                }

                else
                {
                    leftCache.Add(l);
                }
            }
        }, ex =>
        {
            o.OnError(ex);
            disposable.Dispose();
        }, () =>
        {
            lock (gate)
            {
                leftDone = true;

                if (rightDone)
                {
                    o.OnCompleted();
                }
            }
        }).DisposeWith(disposable);

        right.Subscribe(r =>
        {
            lock (gate)
            {
                // Look for the last element, as we want FIFO
                int lastIndex = leftCache.FindLastIndex(x => EqualityComparer<TKey>.Default.Equals(keySelector(x), keySelector(r)));

                if (lastIndex > -1)
                {
                    T element = leftCache[lastIndex];
                    leftCache.RemoveAt(lastIndex);

                    o.OnNext(new Pair<T>(element, r));
                }

                else
                {
                    rightCache.Add(r);
                }
            }
        }, ex =>
        {
            o.OnError(ex);
            disposable.Dispose();
        }, () =>
        {
            lock (gate)
            {
                rightDone = true;

                if (leftDone)
                {
                    o.OnCompleted();
                }
            }
        }).DisposeWith(disposable);

        return disposable;
    });
}

In addition we need the Pair structure that stores the left and right value

public struct Pair<T>
{
    public Pair(T left, T right)
        : this()
    {
        this.Left = left;
        this.Right = right;
    }

    public T Left { get; private set; }

    public T Right { get; private set; }
}

and a small helper method for the CompositeDisposable class (Alternatively you can wrap the subscribe methods in a disposable.Add)

public static T DisposeWith<T>(this T disposable, CompositeDisposable with) where T : class, IDisposable
{
    if(disposable == null)
        throw new ArgumentNullException("disposable");

    if(with == null)
        throw new ArgumentNullException("with");

    with.Add(disposable);

    return disposable;
}

Azure rejects my credit card

Recently, I wanted to give Microsoft Azure a try. Since I'm already registered with Amazon AWS and Google Cloud, a registration with Azure should work too, right?

So I registered with my email address and password, entered my credit card information and pressed the register button.

We can't authorize the payment method. Please make sure the information is correct, or use another payment method. If you continue to get this message, please contact your financial institution.

Wat.

I'm 99.99% sure that I've entered everything correctly and tried it again. Nope, still doesn't work.

After a few days of back and forth with the Azure support, they told me the problem is that my credit card is a Prepaid card. Since I'm from Austria and really only need my credit card for buying small things on the internet, I don't have a different card.

The support also told me:

...the reason why we do not accept the prepaid card is because in past we have seen the subscriptions being disabled due to insufficient funds in the prepaid card.

While I can understand the reasoning behind this, I wonder why AWS and Google Cloud accept my credit card.

Well, seems like no Azure for me.

Link Github issues with Javascript

Here is a quick code snippet that I used in the new Mahapps.Metro News page to link Github issue numbers to their corresponding URL:

$(function() {
  $(".yourclass").each(function(element) {
    var replaced = $(this).html().replace(/(#([0-9]+))/g, '<a href="https://github.com/<your-repo-here>/issues/$2">$1</a>');
    $(this).html(replaced);
  });
})

Since we're keeping our release notes in our repository and just copy paste it into the Github releases section, this is a neat way to avoid linking each issue manually.