摘要:
在 Sceneform-EQR 項目中,原有對 Filament 的使用方式僅依賴官方預編譯產物,Native 層不可控且 SO 體積較大。
為提升工程可維護性並優化產物體積,本文記錄了在不修改 Filament Java API 的前提下,引入 Filament JNI 源碼、合併 filament-android / filament-utils-android / gltfio-android 三個模塊,並統一 JNI_OnLoad 的完整實踐過程。
Sceneform-EQR 集成 Filament JNI 源碼的工程優化實踐
結論:從 Java-only 依賴到 Native 一體化編譯,壓縮 SO 體積 35%+
so庫從4.3M壓縮至2.8M倉庫地址:https://github.com/eqgis/Sceneform-EQR/tree/dev-withFilamentCpp
一、項目優化背景
1. Sceneform-EQR 與 Filament 的現狀
Sceneform-EQR 本質上是一個基於 Filament 的 Android 3D / AR 渲染框架。
在現有工程結構中:
- Java 層:直接依賴 Filament 官方提供的 Java API
- Native 層:使用官方預編譯好的
*.so/*.a產物 -
Filament 模塊拆分:
- filament-android
- filament-utils-android
- gltfio-android
這種方式雖然接入成本低,但在實際工程中逐漸暴露出幾個問題。
2. 原有方案的痛點
(1)SO 體積偏大
Filament 官方 Android 產物以模塊級 so形式存在:
- 多個 so 文件
- 每個 so 內部存在一定符號冗餘
- 無法針對 Sceneform-EQR 的真實使用場景裁剪
最終 APK / AAR 體積不友好
(2)Native 層不可控
- 無法修改 JNI 註冊邏輯
- 無法裁剪不需要的 Native 功能
- 排查 Native Crash 時,只能“對着黑盒猜”
(3)後續深度定製受限
隨着 Sceneform-EQR 後續規劃:
- 自定義渲染管線
- 深度接入 glTF / IBL / 視頻紋理
- 可能修改 Filament JNI 行為
故:必須依賴 Native 源碼
3. 優化目標
綜合考慮,最終確定本次優化目標:
- 引入 Filament JNI 源碼
- 將 filament / utils / gltfio 三個模塊合併為一個 so
- 統一 JNI_OnLoad,消除多 so 衝突
- 在不修改 Java API 的前提下,完成底層重構
- 降低 SO 體積,提升工程可維護性
二、準備階段
1. 準備 Filament 源碼
從官方倉庫獲取 Filament 源碼:
2. 獲取 Android Native 編譯產物
有兩種方式:
- 方式一:自行編譯 Filament
參考filament源碼工程的build.md,按步驟操作即可獲取
- 方式二:直接使用官方 Release
當前推薦方式二,直接下載官方 Release 中的 android-native 產物:
https://github.com/google/filament/releases
解壓後結構如下:
include/→ Filament 頭文件lib/arm64-v8a/*.a→ 靜態庫
三、代碼合併過程
1. Java 層代碼合併
(1)覆蓋 Filament Java API
當前 Sceneform-EQR 未修改 Filament Java 源碼,因此可以直接覆蓋:
com.google.android.filament.android.*
⚠️ 後續 Sceneform-EQR 將會對 Java API 有定製,需通過 Git 進行差異合併。
(2)合併三個 Android 模塊的 Java 源碼
將以下模塊中的 src/main/java 內容合併至 Sceneform-EQR:
- filament-android
- filament-utils-android
- gltfio-android
2. JNI 源碼合併
(1)拷貝 filament-android JNI 源碼
filament-1.67.1/android/filament-android/src/main/cpp
拷貝至:
Sceneform-eqr/cpp/filament-android
(2)同樣處理 gltfio / filament-utils
3. 拷貝 common 代碼
Filament JNI 依賴 common 層工具類:
拷貝至工程中
4. 拷貝 libs 與 third_party
從 Filament 源碼中拷貝 必要的依賴庫:
實踐建議: 只拷貝編譯所需庫,避免 third_party 全量引入
四、解決 JNI_OnLoad 衝突(核心問題)
1. 問題本質
官方 Filament:
- filament-android.so
- filament-utils.so
- gltfio.so
!!!每個模塊都有自己的 JNI_OnLoad!!!
而現在:
- 需要 合併為一個 so
- 只能存在一個 JNI_OnLoad
2. 解決思路
-
各模塊:
- 移除
JNI_OnLoad - 提供
registerXXX()方法
- 移除
-
核心 so:
- 統一
JNI_OnLoad - 手動調用各模塊註冊函數
- 統一
3. 修改 Filament.cpp
extern "C"
JNIEXPORT jint registerFilament(JavaVM* vm, void* reserved) {
JNIEnv* env;
if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
return -1;
}
::filament::VirtualMachineEnv::JNI_OnLoad(vm);
return JNI_VERSION_1_6;
}
4. 修改 Utils.cpp(filament-utils)
extern "C"
JNIEXPORT jint registerUtils(JavaVM* vm, void*) {
...
env->RegisterNatives(...)
return JNI_VERSION_1_6;
}
5. 重寫統一 JNI_OnLoad
extern "C"
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void*) {
registerFilament(vm, nullptr);
registerUtils(vm, nullptr);
return JNI_VERSION_1_6;
}
五、Native 編譯配置
1. 引入 Filament 靜態庫
將 android-native 產物引入工程:
2. CMakeLists 配置
- filament-android
跳轉至git查看:
https://github.com/eqgis/Sceneform-EQR/blob/dev-withFilamentCpp/Eq-Renderer/Android/eq-renderer/src/main/cpp/filament-android/CMakeLists.txt - gltfio-android
跳轉至git查看:
https://github.com/eqgis/Sceneform-EQR/blob/dev-withFilamentCpp/Eq-Renderer/Android/eq-renderer/src/main/cpp/gltfio-android/CMakeLists.txt - filament-utils-android
跳轉至git查看:
https://github.com/eqgis/Sceneform-EQR/blob/dev-withFilamentCpp/Eq-Renderer/Android/eq-renderer/src/main/cpp/filament-utils/CMakeLists.txt
!!!關鍵點:!!!
- 使用
STATIC IMPORTED - 顯式指定
.a路徑 - 嚴格控制
target_link_libraries順序
3. 主模塊 whole-archive
target_link_libraries(eqr-core
-Wl,--whole-archive
filament-jni
filament-utils-jni
gltfio-jni
-Wl,--no-whole-archive
)
否則部分 JNI 符號會被裁剪
4. 頭文件缺失問題
Filament 1.67.1 中:
backend/private未包含在 android-native
解決方案:
從 Filament 源碼工程補拷頭文件
補充説明:當前需採用ndk 27以上版本
六、編譯結果與優化收益
1. 最終 AAR 產物
2. SO 體積對比
| 方案 | SO 大小 |
|---|---|
| 原多 so 方案 | 4.3 MB |
| 合併 JNI 源碼後 | 2.8 MB |
- 合併編譯前
- 合併編譯後
體積減少約 35%
七、小結
本次優化帶來的收益
- SO 體積顯著下降
- Native 層完全可控
- JNI 註冊邏輯清晰統一
- 為 Sceneform-EQR 後續深度定製打下基礎
缺點:Sceneform-EQR升級filament的工作量增大,故以此文備忘~