LoginSignup
11
11

More than 5 years have passed since last update.

AndroidでApache Commons Codecを使う時の注意点

Posted at

Android で Apache Commons Codec を使うと、存在するはずのメソッドを使っているのに、コンパイルエラーや実行時エラーになることがある。

確認環境

Android Studio 2.1.3

build.gradle
android {
    compileSdkVersion 23
    buildToolsVersion "23.0.3"
    useLibrary 'org.apache.http.legacy'
}
dependencies {
    compile 'commons-codec:commons-codec:1.10'
}

コンパイルエラーの例

コード
byte[] bin = "abc".getBytes();
String hex = Hex.encodeHexString(bin);
コンパイルエラー
エラー: シンボルを見つけられません
シンボル:   メソッド encodeHexString(byte[])
場所: クラス Hex

実行時エラーの例

コード
byte[] bin = "abc".getBytes();
String hex = DigestUtils.sha256Hex(bin);
実行時の例外
java.lang.NoSuchMethodError: No static method encodeHexString([B)Ljava/lang/String; in class Lorg/apache/commons/codec/binary/Hex; or its super classes (declaration of 'org.apache.commons.codec.binary.Hex' appears in /system/framework/org.apache.http.legacy.boot.jar)
    at org.apache.commons.codec.digest.DigestUtils.sha256Hex(DigestUtils.java:500)

原因

Android が持つ(Android M では org.apache.http.legacy となった) Apache HTTP Client に古い Commons Codec が内包されており、 build.gradle で指定した新しいバージョンのほうが使われず、古いほうが使われるため。

  • Hex.encodeHexString がコンパイルエラーになるのは、Android側のHexクラス自体にそのメソッドがないため
  • DigestUtils.sha256Hex がコンパイルエラーにならないのは、Android側にはDigestUtilsクラス自体がなく、アプリ側の新しいバージョンに含まれるDigestUtilsが使われるため(?)
    • しかし、DigestUtils.sha256Hexの中で呼ばれているHexクラスはAndroid側のものが使われるから(?)、実行時に NoSuchMethodError となる

Android が持つ Commons Codec ってどのくらい古いのか

ソースコードを見ると、1.3 て書いてある。
https://android.googlesource.com/platform/external/apache-http/+/android-7.0.0_r6/src/org/apache/commons/codec/overview.html#20

対処

Hexクラスの場合は、v1.3に存在するメソッドのほうを使う

byte[] bin = "abc".getBytes();
//String hex = Hex.encodeHexString(bin); こっちはコンパイルエラーになる
char[] hexChars = Hex.encodeHex(bin);
String hex = new String(hexChars);

DigestUtilsなどv1.3に存在しないクラスの場合は、中の実装次第なので、表面上からは判別できない?
とりあえず DigestUtils.sha256Hex は、以下のようにすればok。

byte[] bin = "abc".getBytes();
//String hex = DigestUtils.sha256Hex(bin); こっちはランタイムエラーになる
byte[] sha256 = DigestUtils.sha256(bin);
char[] hexChars = Hex.encodeHex(sha256);
String hex = new String(hexChars);

おまけ

Apache Commons Codec の公式サイトを見ても古ーーい 1.3 の Javadoc が見当たらなかったので、Androidのソースコードから生成してみた。

git clone https://android.googlesource.com/platform/external/apache-http
cd apache-http/
javadoc -locale en_US -public -d doc -sourcepath src -subpackages org.apache.commons.codec

11
11
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
11