PR

FlutterでIsarを使ったらAGP 8.x非互換で詰んだ話——pub-cacheパッチとriverpod_generator競合の解決記録

Flutter

この記事は「詰まった → 原因 → 解決した」の記録です。同じエラーで検索してたどり着いた方の助けになれば幸いです。

→ 個人開発したアプリはこちら:RPG×HIITフィットネスアプリ「MUSCLE QUEST」をリリースしました

環境

項目バージョン
Flutter3.24.5
Dart3.5.4
isar / isar_flutter_libs3.1.0+1
isar_generator3.1.0+1
flutter_riverpod2.6.1
AGP(Android Gradle Plugin)8.3.0
Gradle8.4
Kotlin1.9.22
compileSdk35

問題① isar_flutter_libs で namespace エラーが出る

エラー内容

flutter build apk や flutter run を実行すると、以下のエラーが出てビルドが止まります。

Namespace not specified. Specify a namespace in the module's build file.
See https://d.android.com/r/tools/upgrade-assistant/set-namespace for information about setting the namespace.

FAILURE: Build failed with an exception.
* What went wrong:
A problem occurred configuring project ':isar_flutter_libs'.

原因:AGP 8.x から namespace が必須になった

Android Gradle Plugin(AGP)8.0 以降、すべての Android ライブラリモジュールで build.gradle に namespace の明示的な指定が必須になりました。

しかし isar_flutter_libs 3.1.0+1 は AGP 8.x が普及する前に公開されたバージョンのため、namespace の記述がありません。Isar自体の開発が2023年末に事実上停止しており、パッケージ側での修正は期待できない状況です。

解決策:pub-cache の build.gradle に直接 namespace を追記する

以下のファイルを直接編集します。

~/.pub-cache/hosted/pub.dev/isar_flutter_libs-3.1.0+1/android/build.gradle

android { ... } ブロックの中に namespace を追記します。

gradle

apply plugin: 'com.android.library'

android {
    namespace 'dev.isar.isar_flutter_libs'  // ← この行を追加
    compileSdkVersion 30

    defaultConfig {
        minSdkVersion 16
    }
}

追記後に flutter clean && flutter run を実行するとビルドが通ります。

⚠️ 重要な注意点:flutter pub get で消える

このパッチは pub-cache(パッケージのダウンロードキャッシュ)に直接手を入れています。flutter pub get を実行すると上書きされて消えます。

pubspec.yaml を変更してパッケージを更新するたびに再適用が必要です。CI/CD環境で使う場合はビルドスクリプトにパッチ適用コマンドを組み込む必要があります。

荒技ではありますが、現状これが最も手軽な解決策です。

問題② riverpod_generator と isar_generator が analyzer のバージョンで競合する

エラー内容

riverpod_generator と isar_generator を同時に dev_dependencies に追加して flutter pub get を実行すると、以下のエラーが出て依存関係の解決に失敗します。

Because riverpod_generator >=2.0.0 depends on analyzer ^6.7.0
  and isar_generator >=3.0.0 depends on analyzer <6.0.0,
  riverpod_generator >=2.0.0 is incompatible with isar_generator >=3.0.0.

So, because [your app] depends on both isar_generator ^3.1.0+1
  and riverpod_generator ^2.x.x, version solving failed.

原因:analyzer の要求バージョンが真っ向から衝突している

コード生成系パッケージはどちらも内部で Dart の静的解析エンジン analyzer を使います。

パッケージanalyzer の要求バージョン
riverpod_generator 2.x^6.7.0(6.7以上)
isar_generator 3.x<6.0.0(6未満)

6.7以上 かつ 6未満 を同時に満たすバージョンは存在しません。dependency_overrides で無理やり固定してもどちらかのコード生成が壊れます。

解決策:riverpod_generator を捨てて手動プロバイダーに切り替える

今回は Isar を優先し、riverpod_generator と riverpod_annotation を削除して、flutter_riverpod だけを残す構成にしました。

pubspec.yaml の差分はこうなります。

yaml

dependencies:
  flutter_riverpod: ^2.6.1   # これだけ残す
- riverpod_annotation: ^2.x.x # 削除

dev_dependencies:
  build_runner: ^2.4.13
  isar_generator: ^3.1.0+1
- riverpod_generator: ^2.x.x  # 削除

riverpod_generator を使うと @riverpod アノテーションだけでプロバイダーが自動生成できて便利ですが、手動でも数行追加するだけです。

たとえば @riverpod で書いていたプロバイダーは、手動では以下のように書きます。

dart

// riverpod_generator を使う場合(削除)
// @riverpod
// TimerNotifier timerNotifier(TimerNotifierRef ref) => TimerNotifier();

// 手動プロバイダー(こちらに統一)
final timerProvider =
    StateNotifierProvider.autoDispose<TimerNotifier, TimerState>((ref) {
  return TimerNotifier();
});

記述量は増えますが、動作は完全に同等です。中規模以下のアプリなら手動プロバイダーで十分です。


問題③ AGP バージョンアップで発生した JDK エラー(おまけ)

エラー内容

FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':app:mergeDebugJavaResource'.
> Error while transforming core-for-system-modules.jar ...
  jlink: No value present

原因と解決策

AGP 8.1.0 は JDK の image transform 処理に不具合があり、特定の環境で jlink エラーが発生します。AGP・Gradle・Kotlin のバージョンをセットでアップグレードすることで解消しました。

項目変更前変更後
AGP8.1.08.3.0
Gradle8.1.18.4
Kotlin1.8.x1.9.22

settings.gradle の AGP バージョンと gradle-wrapper.properties の Gradle バージョンは対応関係があります。AGP 8.3.x には Gradle 8.4 以上が必要です。

問題④ package_info_plus・wakelock_plus が AGP 8.x で警告・エラーになる

エラー内容

The option 'android.experimental.legacyTransform' is deprecated
...
PluginException: compileSdkVersion is not specified

解決策:dependency_overrides で古いバージョンに固定

最新バージョンの package_info_plus と wakelock_plus は AGP 8.12+ を前提とした書き方になっており、それ未満の AGP ではビルドエラーになります。dependency_overrides で動作確認済みのバージョンに固定することで回避できます。

yaml

# pubspec.yaml
dependency_overrides:
  package_info_plus: 8.0.2
  wakelock_plus: 1.2.8

dependency_overrides は直接依存していないパッケージのバージョンを強制的に上書きします。他のパッケージが内部でこれらに依存していても指定バージョンが使われます。

問題⑤ Isar.getDir() が存在しないというコンパイルエラー

エラー内容

The method 'getDir' isn't defined for the type 'Isar'.
Try correcting the name to the name of an existing method.

原因と解決策

ネット上の Isar のサンプルコードには Isar.getDir() を使う例が多く見られますが、isar 3.1.0+1 にはこのメソッドが存在しません。path_provider パッケージで取得したパスを渡す書き方が正しい実装です。

dart

// NG:ネット上によくある古い書き方
final dir = await Isar.getDir();

// OK:path_provider で取得する
import 'package:path_provider/path_provider.dart';

final dir = await getApplicationDocumentsDirectory();
final isar = await Isar.open(
  [UserProfileSchema, WorkoutSessionSchema, AchievementSchema],
  directory: dir.path,
  inspector: kDebugMode, // デバッグ時だけ Isar Inspector を有効化
);

まとめ:詰まりポイントと解決策の一覧

問題原因解決策
namespace not specifiedAGP 8.x が namespace 必須にpub-cache の build.gradle に手動追記
riverpod_generator と isar_generator の競合analyzer の要求バージョンが両立不可riverpod_generator を削除、手動プロバイダーに統一
jlink エラーAGP 8.1.0 の不具合AGP 8.3.0 + Gradle 8.4 + Kotlin 1.9.22 にアップグレード
package_info_plus / wakelock_plus のエラーAGP 8.12+ を前提とした実装dependency_overrides で旧バージョンに固定
Isar.getDir() が存在しない3.1.0+1 にそのメソッドがないpath_provider の getApplicationDocumentsDirectory() を使う

おわりに

Isar はローカル DB として高速かつ型安全で非常に使いやすいパッケージですが、AGP 8.x 以降の Android ビルド環境との相性問題が複数存在します。開発が停止気味であるため今後のアップデートも期待しにくい状況です。

新規プロジェクトでローカル DB を選定する場合は、継続的にメンテナンスされている drift や sqflite も検討する価値があります。

今回紹介した問題は、筆者が個人開発してリリースした RPG 風 HIIT フィットネスアプリ「MUSCLE QUEST」の開発中に実際に遭遇したものです。同じ構成で詰まっている方の参考になれば幸いです。

最後まで読んでいただきありがとうございました。

→ MUSCLE QUESTの詳細はこちら:RPG×HIITフィットネスアプリ「MUSCLE QUEST」をリリースしました→ Flutter備忘録はこちら:Flutter リリースビルド時にAPIが利用できないときの対応法

コメント