給中介軟體供應商的建議

發布使用 NDK 建構的中介軟體時會引發其他問題,但應用程式開發人員無需為此感到擔心。預建程式庫會為使用者提供一些實作選項。

選擇 API 級別和 NDK 版本

您的使用者使用的 minSdkVersion 版本不能比您低。如果使用者的應用程式需要在 API 21 上執行,您就無法針對 API 24 進行建構。您可以針對「低於」使用者的 API 級別建構程式庫,例如針對 API 16 建構程式庫,並保持與 API 21 使用者相容。

各 NDK 版本大多彼此相容,但版本間的變更偶爾會破壞相容性。如果您確定所有使用者都使用相同的 NDK 版本,則建議您也使用與使用者相同的版本,不然就是使用最新版本。

使用 STL

若您正在編寫 C++ 和使用 STL,並且要發布共用程式庫,那麼您在 libc++_sharedlibc++_static 之間的選擇將會對使用者造成影響。如果您要發布共用程式庫,則必須使用 libc++_shared,或確保程式庫不會公開 libc++ 的符號。最佳做法是使用版本指令碼明確宣告您的 ABI 介面 (這樣也有助於保持實作細節的私密性)。例如,一個簡單的算術程式庫可能包含下列版本指令碼:

LIBMYMATH {
global:
    add;
    sub;
    mul;
    div;
    # C++ symbols in an extern block will be mangled automatically. See
    # https://stackoverflow.com/a/21845178/632035 for more examples.
    extern "C++" {
        "pow(int, int)";
    }
local:
    *;
};

建議優先使用版本指令碼,因為這是控制符號瀏覽權限最可靠的方法。這對於「所有」共用程式庫 (無論是否為中介軟體) 而言都是最佳做法,因為這可以防止實作細節外洩,並縮短載入時間。

另一個較不可靠的做法是連結時使用 -Wl,--exclude-libs,libc++_static.a -Wl,--exclude-libs,libc++abi.a。這種做法較不可靠,因為它只會隱藏程式庫中已明確命名的符號,並且不會為未使用的程式庫報告診斷結果 (程式庫名稱中的錯字並非錯誤,並且使用者應負責及時更新程式庫清單)。這種做法也不會隱藏您自己的實作細節。

在 AAR 中發布原生資料庫

Android Gradle 外掛程式可匯入以 AAR 形式發布的原生依附元件。如果您的使用者採用的是 Android Gradle 外掛程式,這對他們而言將是最簡單的程式庫使用方式。

原生資料庫可以透過 AGP 封裝為 AAR。如果您已透過 externalNativeBuild 建構程式庫,這便是最簡單的方法。

非 AGP 建構可以使用 ndkport,或按照 Prefab 文件中的說明進行手動封裝,以便建立 AAR 的 prefab/ 子目錄。

包含 JNI 程式庫的 Java 中介軟體

請務必謹慎處理包含 JNI 程式庫的 Java 程式庫 (即包含 jniLibs 的 AAR),這樣包含的 JNI 程式庫才不會與使用者應用程式中的其他程式庫產生衝突。例如,如果 AAR 包含的 libc++_shared.so 版本與應用程式使用的 libc++_shared.so 版本不同,則只有一個版本會安裝到 APK,而且這可能會引發不可靠的行為。

最可靠的解決方案是確保 Java 程式庫中的 JNI 程式庫不超過一個 (這同樣適用於應用程式)。包含 STL 在內的所有依附元件都應該以靜態方式連結至實作程式庫,並且應該使用版本指令碼強制執行 ABI 介面。例如,包含 JNI 程式庫 libfooimpl.so 的 Java 程式庫 com.example.foo,應使用下列版本指令碼:

LIBFOOIMPL {
global:
    JNI_OnLoad;
local:
    *;
};

這個範例按照 JNI 提示中的說明,透過 JNI_OnLoad 使用 registerNatives 來確保盡量不公開 ABI 介面,同時盡可能縮短程式庫載入時間。