NDK로 빌드된 미들웨어를 배포하다 보면 몇 가지 부가적인 문제가 발생하는데 앱 개발자는 이에 대해 걱정하지 않아도 됩니다. 사전 빌드된 라이브러리는 사용자에게 몇 가지 구현 옵션을 제시합니다.
API 수준 및 NDK 버전 선택
앱 사용자는 개발자보다 낮은 minSdkVersion을 사용할 수 없습니다. 즉, 사용자가 앱을 API 21에서 실행해야 한다면 앱을 API 24용으로 빌드해서는 안 됩니다. 사용자보다 낮은 API 수준으로 라이브러리를 빌드하는 것은 괜찮습니다. API 16용으로 빌드한다면 API 21 사용자와의 호환성을 유지하면 됩니다.
NDK 버전은 대부분 서로 호환되지만 경우에 따라 변경사항으로 인해 호환성이 무너지기도 합니다. 모든 사용자가 동일한 버전의 NDK를 사용하고 있다면 같은 버전을 사용하는 것이 가장 좋습니다. 그렇지 않으면 최신 버전을 사용하세요.
STL 사용
C++를 작성하며 STL을 사용하는 경우 공유 라이브러리를 배포하면 libc++_shared와 libc++_static 중 개발자가 선택한 옵션이 사용자에게 적용됩니다. 공유 라이브러리를 배포한다면 libc++_shared를 사용하거나 libc++의 기호가 라이브러리에서 노출되지 않도록 해야 합니다. 이를 위한 가장 좋은 방법은
버전 스크립트를 사용하여 ABI 노출 영역을 명시적으로 선언합니다.
또 다른 옵션은 연결 시 -Wl,--exclude-libs,libc++_static.a
-Wl,--exclude-libs,libc++abi.a를 사용하는 것입니다. 이 옵션은 명시적으로 이름이 지정된 라이브러리에서 기호만 숨기고 사용되지 않는 라이브러리 진단은 보고되지 않으므로 덜 강력합니다(라이브러리 이름의 오타는 오류가 아니며 라이브러리 목록을 최신 상태로 유지하는 것은 사용자 책임). 이 접근 방식은 구현 세부정보를 숨기지 않습니다.
AAR로 네이티브 라이브러리 배포
Android Gradle 플러그인은 AAR로 배포된 네이티브 종속 항목을 가져올 수 있습니다. 이는 사용자가 Android Gradle 플러그인(AGP)을 사용 중인 경우 라이브러리를 사용하기에 가장 간편한 방법입니다.
AGP를 사용하여 네이티브 라이브러리를 Android 보관 파일(AAR)로 패키징할 수 있습니다. 이는 라이브러리가 externalNativeBuild로 이미 빌드된 경우 가장 쉬운 옵션입니다.
AGP 이외의 빌드는 ndkports를 사용하거나 AAR의 prefab/ 하위 디렉터리를 만드는 방법을 안내하는 Prefab 도움말에 따라 직접 패키징할 수 있습니다.
JNI 라이브러리를 포함하는 자바 미들웨어
JNI 라이브러리를 포함하는 자바 라이브러리(jniLibs를 포함하는 AAR)는 포함된 JNI 라이브러리가 사용자가 설치한 앱의 다른 라이브러리와 충돌하지 않도록 주의해야 합니다. 예를 들어 AAR에 libc++_shared.so가 포함되어 있지만 앱이 사용하는 것과 다른 libc++_shared.so 버전이라면 APK에 둘 중 하나만 설치되고 동작이 불안정해질 수 있습니다.
가장 안정적인 해결 방법은 자바 라이브러리에 하나의 JNI 라이브러리만 포함하는 것입니다. 이는 앱에도 적용되는 사항입니다. STL을 포함한 모든 종속 항목은 구현 라이브러리에 정적으로 연결해야 하며, 버전 스크립트를 사용하여 ABI 표면을 적용해야 합니다. 예를 들어 JNI 라이브러리 libfooimpl.so를 포함하는 자바 라이브러리 com.example.foo는 다음 버전 스크립트를 사용해야 합니다.
LIBFOOIMPL{global:JNI_OnLoad;local:*;};
이 예에서는 JNI 도움말의 설명대로 JNI_OnLoad를 통해 registerNatives를 사용하여 최소 ABI 표면이 노출되고 라이브러리 로드 시간이 최소화되도록 합니다.
이 페이지에 나와 있는 콘텐츠와 코드 샘플에는 콘텐츠 라이선스에서 설명하는 라이선스가 적용됩니다. 자바 및 OpenJDK는 Oracle 및 Oracle 계열사의 상표 또는 등록 상표입니다.
최종 업데이트: 2025-07-27(UTC)
[[["이해하기 쉬움","easyToUnderstand","thumb-up"],["문제가 해결됨","solvedMyProblem","thumb-up"],["기타","otherUp","thumb-up"]],[["필요한 정보가 없음","missingTheInformationINeed","thumb-down"],["너무 복잡함/단계 수가 너무 많음","tooComplicatedTooManySteps","thumb-down"],["오래됨","outOfDate","thumb-down"],["번역 문제","translationIssue","thumb-down"],["샘플/코드 문제","samplesCodeIssue","thumb-down"],["기타","otherDown","thumb-down"]],["최종 업데이트: 2025-07-27(UTC)"],[],[],null,["# Advice for middleware vendors\n\nDistributing middleware built with the NDK raises some additional issues that\napp developers do not need to worry about. Prebuilt libraries impose some of\ntheir implementation choices on their users.\n\nChoosing API levels and NDK versions\n------------------------------------\n\nYour users cannot use a [minSdkVersion](/ndk/guides/sdk-versions#minsdkversion) lower than yours. If your users' apps\nneed to run on API 21, you cannot build for API 24. It is okay to build your\nlibrary for a *lower* API level than your users. You can build for API\n16 and remain compatible with your API 21 users.\n\nNDK versions are largely compatible with each other, but occasionally there are\nchanges that break compatibility. If you know that all of your users are using\nthe same version of the NDK, it's best to use the same version that they do.\nOtherwise, use the newest version.\n\nUsing the STL\n-------------\n\nIf you're writing C++ and using the STL, your choice between `libc++_shared` and\n`libc++_static` affects your users if you distribute a shared library. If you\ndistribute a shared library, you must either use `libc++_shared` or ensure that\nlibc++'s symbols are not exposed by your library. The best way to do this is to\nexplicitly declare your ABI surface with a [version script](/ndk/guides/this%20also%20helps%0Akeep%20your%20implementation%20details%20private).\n\nAnother, less robust option is to use `-Wl,--exclude-libs,libc++_static.a\n-Wl,--exclude-libs,libc++abi.a` when linking. This is less robust because it\nwill only hide the symbols in the libraries that are explicitly named, and no\ndiagnostics are reported for libraries that are not used (a typo in the library\nname is not an error, and the burden is on the user to keep the library list up\nto date). This approach also does not hide your own implementation details.\n\nDistributing native libraries in AARs\n-------------------------------------\n\n| **Note:** This section describes how to distribute C/C++ *APIs* to users. If your native libraries are implementation details of your *Java* API, see the [Java\n| middleware with JNI libraries](#java_middleware_with_jni_libraries) section.\n\nThe Android Gradle plugin can import [native dependencies](/studio/build/dependencies#using-native-dependencies) distributed in\n[AARs](/studio/projects/android-library). If your users are using the Android Gradle plugin, this will be the\neasiest way for them to consume your library.\n\nNative libraries can be packaged into an AAR [by\nAGP](/studio/releases/gradle-plugin#4.1-prefab-publish). This will be the\neasiest option if your library is already built by [externalNativeBuild](/reference/tools/gradle-api/current/com/android/build/api/dsl/ExternalNativeBuild).\n\nNon-AGP builds can use [ndkports](https://android.googlesource.com/platform/tools/ndkports/), or perform manual packaging by following the\n[Prefab](https://google.github.io/prefab/) documentation to create the `prefab/` subdirectory of their AAR.\n\nJava middleware with JNI libraries\n----------------------------------\n\nJava libraries that include JNI libraries (in other words, AARs that contain\n`jniLibs`) need to be careful that the JNI libraries they include will not\ncollide with other libraries in the user's app. For example, if the AAR includes\n`libc++_shared.so`, but a different version of `libc++_shared.so` than the app\nuses, only one will be installed to the APK and that may lead to unreliable\nbehavior.\n| **Warning:** [Bug 141758241](https://issuetracker.google.com/141758241): Older versions of the Android Gradle plugin do not currently diagnose this error condition. One of the identically named libraries will be arbitrarily chosen for packaging in the APK.\n\nThe most reliable solution is for Java libraries to include no more than **one**\nJNI library (this is good advice for apps too). All dependencies including the\nSTL should be statically linked into the implementation library, and a version\nscript should be used to enforce the ABI surface. For example, a Java library\n`com.example.foo` that includes the JNI library `libfooimpl.so` should use the\nfollowing version script: \n\n LIBFOOIMPL {\n global:\n JNI_OnLoad;\n local:\n *;\n };\n\nThis example uses `registerNatives` via `JNI_OnLoad` as described in [JNI Tips](/training/articles/perf-jni#native-libraries)\nto ensure that the minimal ABI surface is exposed and library load time is\nminimized."]]