retlat's blog

AndroidからJDBC DriverでPostgreSQLに接続

ちょっと作りたいものがあるので, AndroidからDocker Desktop for Macで動かしているPostgreSQLにJDBC Driverで接続できるか実験

環境

  • Android Studio 3.5.2
  • Android Emulator 29.2.1
  • Nexus 5
  • PostgreSQL JDBC Driver 42.2.8
  • postgres:11.5 Docker image

実験用ソース

Android Studioの Start a new Android Studio Project から, Empty ActivityでMinimum API level 23なプロジェクトを作る
これに必要な分をちょっとだけいれたものを使う
まずはapp/build.gradleのdependenciesにドライバを追加する

dependencies {
    // 略
    implementation 'org.postgresql:postgresql:42.2.8'
    // 略
}

次に適当な接続してSQLを実行するコードを, MainActivity.ktに追加する

override fun onResume() {
    super.onResume()

    thread {
        val c = DriverManager.getConnection("jdbc:postgresql://10.0.2.2/postgres?user=postgres&password=password")
        val s = c.createStatement()
        val r = s.executeQuery("CREATE TABLE IF NOT EXISTS sample (id SERIAL PRIMARY KEY, number INTEGER)")
        r.close()
        s.close()
        c.close()
    }
}

ネットワークアクセスするのでパーミッションの記述をAndroidManifest.xmlに追加する

+ <uses-permission android:name="android.permission.INTERNET" />

Emulator と実機の比較

最近の端末を持っていないのでエミュレータを使うとして, 実機と同じように動作するかテストする
Android 6.0.1がインストールされたNexusとAPI 23のエミュレータで実行したところ, 同じように以下のExceptionが出力された
カスタマイズして出荷されている可能性があるので一概に言えないが, とりあえずエミュレータが実機と同じように動作すると判断する

E/AndroidRuntime: FATAL EXCEPTION: Thread-147
    Process: com.example.sample, PID: 2812
    java.sql.SQLException: No suitable driver
        at java.sql.DriverManager.getConnection(DriverManager.java:186)
        at java.sql.DriverManager.getConnection(DriverManager.java:144)
        at com.example.sample.MainActivity$onResume$1.invoke(MainActivity.kt:19)
        at com.example.sample.MainActivity$onResume$1.invoke(MainActivity.kt:8)
        at kotlin.concurrent.ThreadsKt$thread$thread$1.run(Thread.kt:30)

実験

いろいろなバージョンで試してみる
とりあえず上の実験でAPI 23はダメだったので, それ以降を順次試す
API 24, 25はクラスが見つからないのでダメ

java.lang.NoClassDefFoundError: Failed resolution of: Ljava/time/Duration;
 Caused by: java.lang.ClassNotFoundException: Didn't find class "java.time.Duration" on path: DexPathList[[zip file "/data/app/com.example.sample-1/base.apk"],nativeLibraryDirectories=[/data/app/com.example.sample-1/lib/x86_64, /system/lib64, /vendor/lib64]]

API 26から29はExceptionがthrowされているものの, SQLを実行した結果なのでOK

org.postgresql.util.PSQLException: No results were returned by the query.

追加実験 (追記: 2019/12/30)

API 24のExceptionはJava 8およびAPI 26で追加された java.time.Duration を使っているからダメなだけで, DriverをJava 7用にしたら問題なかったのではと思い立ったので実験
app/build.gradleのdependenciesを以下のように書き換える

  dependencies {
      // 略
-     implementation 'org.postgresql:postgresql:42.2.8'
+     implementation 'org.postgresql:postgresql:42.2.8.jre7'
      // 略
  }

他は変更せずに動かしてみるとAPI 26以降と同じ org.postgresql.util.PSQLException が投げられたので接続OK

結論

Android 7.0 NougatからJDBC DriverでPostgreSQLに接続できる
なおAndroid 7.0, 7.1 はJava 7用を使う必要があるが, Android 8.0 OreoからはJava 8用で構わない
ただし端末による

Post: 2019-11-15 Update: 2021-08-18
Tags: Android