android.net.Uri breaks IPv6 addresses in the wrong places

Just a little word of caution to developers who are using Android’s convenient android.net.Uri class instead of the more battle-tested java.net.URI. It doesn’t understand IPv6 literal addresses and can break your app when you try to separate hosts and ports from them. This can cause issues for your app in many instances so better avoid using it altogether.

import android.net.Uri;
Uri address1 = new Uri.parse("http://[2001:db8::dead:e1f]/");
address1.toHost();
// "[2001"

Android is clearly indiscriminately splitting the hostname out of the address at the first colon, completely disregarding the Format for Literal IPv6 Addresses in URL standard (RFC 2732.) Depending on the IPv6 address we’re dealing with, the .getPort() method can also return something similar. It’s an easy implementation mistake to make and it works quite nicely in Java’s own URI class:

import java.net.URI;
URI address2 = new URI("http://[2001:db8::dead:e1f]/");
address2.getHost();
// "[2001:db8::dead:e1f]"

A lot of Android system calls, especially those in the android.net package will return Uri objects rather than a URI. Meaning there are likely a lot of apps out there that wouldn’t understand an IPv6 literal address if they ever came across one. Developers can still recover data from a Uri object through a little round-tripping dance through its .toString() method and turning that back into a URI object:

URI address3 = new URI((Uri) address1);
address3.getHost();
// "[2001:db8::dead:e1f]"

I hope you found this before one of your app’s users complained that IPv6 literal addresses misbehaved and triggered an exception in a network call.

I reported the problem as Android bug #192855. Although meeting every definition of a spec violation and a bug, I doubt this will get fixed anytime soon due to the slow Android update rollout schedule.

Update (): This issue remains unresolved more than a year later. I’ve reached out to folks at Google as their bug tracker appears to ever reach anyone but have gotten nowhere.

Update (): Three years later, and the issue is now resolved as fixed in the Android Open Source Project bug tracker. However, don’t expect this to be fixed on devices until after Android API Level 29 or maybe even 30 (after Android 9.0 “Pie”.)