概要
以下のように StandardCharsets.UTF_8.toString() をエンコーディングの指定として渡すと、一部の Android 端末で IllegalCharsetNameExceptionが返ってくるので調査しました。
URLDecoder.decode("%2F%2F", StandardCharsets.UTF_8.toString())
java.nio.charset.IllegalCharsetNameException: java.nio.charset.CharsetICU[UTF-8]
at java.nio.charset.Charset.checkCharsetName(Charset.java:201)
at java.nio.charset.Charset.forName(Charset.java:295)
at java.net.URLDecoder.decode(URLDecoder.java:60)
at com.example.test.TheTest.Test(TheTest.kt:26)
解決方法
StandardCharsets.UTF_8.toString()
を
StandardCharsets.UTF_8.name()
とするだけ。
原因
Android 6 以下の端末は OpenJDK を使用していないので、Charset 周りの実装が今と微妙に異なります。
Android 6 の実装
// https://cs.android.com/android/platform/superproject/+/android-6.0.1_r81:libcore/luni/src/main/java/java/nio/charset/Charset.java
@Override
public final String toString() {
return getClass().getName() + "[" + this.canonicalName + "]";
}
Android 7 以降の実装
// https://cs.android.com/android/platform/superproject/+/master:libcore/ojluni/src/main/java/java/nio/charset/Charset.javajava/nio/charset/Charset.java;l=1?q=Charset.java&sq=
public final String toString() {
return name();
}
このように Android 6 以下の場合は debug 表示用の文字列を返すコードになっていたのが原因だったようです。実装を見てる感じ Android のバージョン関係なく toStringよりname()を呼んだ方が良さそうですね。