prefabってなんやねん
Android developersのAndroid Gradle プラグインのネイティブ依存関係によると、ネイティブライブラリの依存関係をaarライブラリに含めて配布&使うようにするAndroid Gradle Plugin(AGP)の仕組みということみたいです。
詳しくはAndroid developersを見てもらうことにして、とりあえずprefabを使ってaarでネイティブライブラリを公開してみたです。
特徴
よいことも悪いことも色々と…
- ネイティブライブラリの依存関係をaarに含めて配布できる。
つまり、ヘッダーファイルだとか共有ライブラリをJavaのクラスが生き別れになってUnsatisfiedLinkErrorでわけわからんくなることがなくなる…かもしれない。 - NDKでのビルド時にAGPが自動的に依存関係を挿入してくれるので手作業で共有ライブラリやヘッダーファイルを設定する必要がなくなる…かもしれない。
- 1つのモジュールにつき1つのヘッダーファイルディレクトリしか指定できない、コレ結構面倒くさい。
- おなじプロジェクトの別モジュールのaarをprefabの対象として使うことはできない。
- STL=c++_sharedが実質的に必須。
- aarに含まれるネイティブライブラリをビルドしたときのNDKバージョンと使う側のアプリ/モジュールでビルドするときのNDKバージョンが異なるとトラブることが多い。
- prefabを含むaarが巨大になる😱
- うまく依存関係を解決できないことが多いナンデヤネン
- prefab作成時のインクルードファイルの相対パスと、prefabを使うときのインクルードファイルの相対パスが同じになるようにした方がトラブりにくい。
作ってみた
作るだけなら簡単✌️
Android developersに書いてあるとおり、
prefabPublishing をtrueにして、prefab項目内に公開したいネイティブライブラリを記述だけです。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
buildFeatures { prefabPublishing true } prefab { mylibrary { headers "src/main/cpp/mylibrary/include" } myotherlibrary { headers "src/main/cpp/myotherlibrary/include" } } |
ここで気をつけないといけないのは2点です。
- 「headers」であるにもかかわらず、ヘッダーファイルディレクトリとして指定できるのは1つだけ。
- ネイティブライブラリ名にハイフン「-」を含む場合には記述に注意が必要。
1つ目のヘッダーファイルディレクトリとして指定できるのは1つだけというのはissuesにも上がっていますが、今のところ修正される見込みはなさそうです。
ただし、下位ディレクトリまで再帰的に含めてくれますので、ヘッダーファイルのディレクトリの構造を工夫して、複数のディレクトリを含む上位ディレクトリを指定するようにするととりあえずはいけそうです。
ただし複数のネイティブライブラリが同じディレクトリを参照してしまうと同じヘッダーファイルがあっちこっちに含まれて肥大化することになるので注意が必要です。
2つ目のネイティブライブラリ名にハイフン「-」を含む場合についてはAndroid developersやぐるぐる先生のお告げには明確な記述がありません。
なので、自分のネイティブライブラリにハイフン「−」を含む場合にはわけわからんエラーが出て途方に暮れることになります。
こんな感じで大量にエラーが出ますが、これをみてライブラリ名にハイフンが含まれているからだとわかる人はほとんど居ないと思います。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
Build file '/Volumes/SSD/saki/projects/aAndUsb/aandusb/build.gradle' line: 3 A problem occurred evaluating project ':aandusb'. > No signature of method: build_5kzejclr7omgh63luky3gam65.android() is applicable for argument types: (build_5kzejclr7omgh63luky3gam65$_run_closure1) values: [build_5kzejclr7omgh63luky3gam65$_run_closure1@6a36d7dc] * Try: Run with --info or --debug option to get more log output. Run with --scan to get full insights. * Exception is: org.gradle.api.GradleScriptException: A problem occurred evaluating project ':aandusb'. at org.gradle.groovy.scripts.internal.DefaultScriptRunnerFactory$ScriptRunnerImpl.run(DefaultScriptRunnerFactory.java:93) at org.gradle.configuration.DefaultScriptPluginFactory$ScriptPluginImpl.lambda$apply$0(DefaultScriptPluginFactory.java:133) at org.gradle.configuration.ProjectScriptTarget.addConfiguration(ProjectScriptTarget.java:77) at org.gradle.configuration.DefaultScriptPluginFactory$ScriptPluginImpl.apply(DefaultScriptPluginFactory.java:136) at org.gradle.configuration.BuildOperationScriptPlugin$1.run(BuildOperationScriptPlugin.java:65) at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:29) at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:26) at org.gradle.internal.operations.DefaultBuildOperationRunner$3.execute(DefaultBuildOperationRunner.java:75) at org.gradle.internal.operations.DefaultBuildOperationRunner$3.execute(DefaultBuildOperationRunner.java:68) at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:153) at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:68) at org.gradle.internal.operations.DefaultBuildOperationRunner.run(DefaultBuildOperationRunner.java:56) at org.gradle.internal.operations.DefaultBuildOperationExecutor.lambda$run$1(DefaultBuildOperationExecutor.java:71) at org.gradle.internal.operations.UnmanagedBuildOperationWrapper.runWithUnmanagedSupport(UnmanagedBuildOperationWrapper.java:45) at org.gradle.internal.operations.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:71) at org.gradle.configuration.BuildOperationScriptPlugin.lambda$apply$0(BuildOperationScriptPlugin.java:62) at org.gradle.configuration.internal.DefaultUserCodeApplicationContext.apply(DefaultUserCodeApplicationContext.java:43) at org.gradle.configuration.BuildOperationScriptPlugin.apply(BuildOperationScriptPlugin.java:62) at org.gradle.api.internal.project.DefaultProjectStateRegistry$ProjectStateImpl.lambda$applyToMutableState$0(DefaultProjectStateRegistry.java:248) ... 140 more |
このときのprefabセクションの記述はこうなっていました。「libmedia-backport.so」をaarに含めようとしていたわけですが、先ほどのような意味不明な大量のエラーが出力されます。
1 2 3 4 5 6 7 |
prefab { ... media-backport { headers "../sources/include/media-backport" } 。。。 } |
対策は、わかってみれば簡単なのですが、先ほどのprefabセクションを少し書き換えます。
nameで実際のネイティブライブラリ名(先頭の「lib」を取り除いて拡張子もなし)を指定します。nameを指定しない場合にはセクション名がnameとして解釈されるのでライブラリ名にハイフンを含まなければname指定は不要なのですが、セクション名にはハイフンを含めることができないのです。
1 2 3 4 5 6 7 8 |
prefab { ... mediabackport { name "media-backport" headers "../sources/include/media-backport" } 。。。 } |
このときのaar内の構造をAndroid Studioで見るとこのようになります。ちゃんとmedia-backportが公開されていますね。
ということでaarでネイティブをライブラリを公開してみたでした。
次回はaarに含めたネイティブライブラリへリンクしてビルドしてみるよ(^.^)/~~~
コメント
[…] 前回はaarでネイティブライブラリを公開する話でした。 今回はそのaar内に含まれるネイティブライブラリへリンクした別のネイティブライブラリを作ってみた話です。 […]