System.loadLibrary (…) 내 경우에는 네이티브 라이브러리를 찾을 수 없습니다.


91

다른 Android 프로젝트 의 기존 네이티브 라이브러리를 사용하고 싶기 때문에 NDK 빌드 라이브러리 ( libcalculate.so )를 새 Android 프로젝트에 복사했습니다 . 새 Android 프로젝트에서 폴더 libs/armeabi/만들고 거기 에 libcalculate.so를 넣었 습니다. jni / 폴더 가 없습니다 . 내 테스트 장치에는 ARM 아키텍처가 있습니다.

내 자바 코드에서 다음과 같이 라이브러리를로드합니다.

  static{
    System.loadLibrary("calculate");
  }

새 Android 프로젝트를 실행할 때 오류가 발생했습니다.

java.lang.UnsatisfiedLinkError:  ...
nativeLibraryDirectories=[/vendor/lib, /system/lib]]] couldn't find "libcalculate.so"

따라서 오류가 말했듯이 복사 된 네이티브 라이브러리가 / verdor / lib 또는 / system / lib에 없습니다.이 문제를 해결하는 방법은 무엇입니까?

(lib / 아래에 libcalculate.so가 있습니다.)

==== 업데이트 =====

또한 프로젝트 루트 아래에 jni / 폴더를 만들고 jni / 아래에 Android.mk 파일을 추가하려고했습니다. Android.mk의 내용은 다음과 같습니다.

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)
LOCAL_MODULE    := libcalculate
LOCAL_SRC_FILES := libcalculate.so
include $(PREBUILT_SHARED_LIBRARY)

그런 다음 프로젝트 루트에서 ndk-build를 실행했습니다. 그 후, armeabi / 및 armeabi-v7a / 디렉토리는 ndk-build (폴더 안에 libcalculate.so 포함)에 의해 생성됩니다.

그런 다음 내 maven을 실행하여 프로젝트를 성공적으로 빌드합니다. 최종 apk 패키지에는 다음이 있습니다.

lib/armeabi/libcalculate.so
lib/armeabi-v7a/libcalculate.so

하지만 내 앱을 실행할 때 동일한 오류가 발생합니다.

java.lang.UnsatisfiedLinkError:  ...
nativeLibraryDirectories=[/vendor/lib, /system/lib]]] couldn't find "libcalculate.so"

3
라이브러리를 바로 아래에 두었 libs/습니까? 지원하려는 대상 ABI 당 하나의 하위 디렉터리 (armeabi, armeabi-v7a, x86, mips 등)를 만들고 각 하위 디렉터리에 적절한 .so 파일을 배치해야 할 수 있습니다 (예 : armeabi 용으로 빌드 된 .so 파일은 libs/armeabi/, 기타).
Michael

@Michael, 난 그냥 내 게시물에, 나는 실제로 libs와 아래 / armeabi / 넣어 놓친
user842225

libcalculate.so가 실제로 패키징 프로세스에 의해 선택되는지 확인합니다. 예를 들어를 시도 unzip -l package.apk하거나 apk의 이름을 .zip으로 변경하고 일부 응용 프로그램으로 엽니 다. 그렇지 않은 경우 패키징하는 데 문제가있는 것입니다 (IDE에서 폴더가 있음을 인식 했습니까? 프로젝트를 새로 고쳐야합니까?).
mstorsjo

@mstorsjo, 나는 lib 디렉토리에서 / libcalculate.so이의 APK 패키지를 unziped
user842225

1
Android.mk 또는 컴파일 관련 파일이 필요하지 않습니다. : 그냥 여기에 같은 jniLibs 그들의 따라 하위 디렉토리에있는 파일 수 있도록를 넣어 github.com/Ph1b/MaterialAudiobookPlayer/tree/master/audiobook/...
폴 Woitaschek

답변:


177

근본 원인 (동시에 문제를 해결할 수 있음)을 위해 다음과 같이 할 수 있습니다.

  1. jni 폴더와 모든 .mk 파일을 제거 합니다. 아무것도 컴파일하지 않으면 이것도 NDK도 필요하지 않습니다.

  2. 당신의 복사 libcalculate.so파일 내부 <project>/libs/(armeabi|armeabi-v7a|x86|...). Android Studio를 사용할 때는 <project>/app/src/main/jniLibs/(armeabi|armeabi-v7a|x86|...)이지만 이클립스를 사용하고 있습니다.

  3. APK를 빌드하고 zip 파일 로 열어 libcalculate.so파일이 lib / (armeabi | armeabi-v7a | x86 | ...) 안에 있는지 확인합니다 .

  4. 애플리케이션 제거 및 설치

  5. dumpsys 패키지 패키지 실행 | yourpackagename grep을 얻가하는 nativeLibraryPath 또는 legacyNativeLibraryDir 응용 프로그램의합니다.

  6. 가지고 있는 nativeLibraryPath 또는 legacyNativeLibraryDir / armeabi 에서 ls 를 실행 하여 libcalculate.so가 실제로 있는지 확인합니다.

  7. 존재하는 경우 원본 libcalculate.so 파일 에서 변경되지 않았는지 확인 합니다. 올바른 아키텍처에 대해 컴파일 되었는지 , 예상되는 기호를 포함하는지, 누락 된 종속성이 있는지 확인합니다. readelf를 사용하여 libcalculate.so를 분석 할 수 있습니다.

5-7 단계를 확인하려면 명령 줄 및 readelf 대신 내 애플리케이션을 사용할 수 있습니다. Native Libs Monitor

추신 : 기본적으로 .so 파일을 배치하거나 생성해야하는 위치에 대해 혼동하기 쉽습니다. 다음은 요약입니다.

  • Eclipse 프로젝트 내의 libs / CPU_ABI

  • Android Studio 프로젝트 내의 jniLibs / CPU_ABI

  • AAR 내부의 jni / CPU_ABI

  • 최종 APK 내부의 lib / CPU_ABI

  • 앱 내부 nativeLibraryPath A의 <5.0에있어서, 상기 응용 프로그램의 내부 legacyNativeLibraryDir / CPU_ARCH A의> = 5.0 장치.

여기서 CPU_ABIarmeabi, armeabi-v7a, arm64-v8a, x86, x86_64, mips, mips64 중 하나 입니다. 대상 아키텍처와 라이브러리가 컴파일 된 아키텍처에 따라 다릅니다.

당신은 당신이 사용중인의 전체 세트의 내부에있는 lib 디렉토리 필요 libs와는 CPU_ABI 디렉토리 사이에 혼합되지도 않습니다 armeabi 에 설치되지 않습니다 폴더 armeabi-V7A의 내부 어떠한 libs가있는 경우 장치 armeabi을 -v7a 폴더.


3
고마워요! Android Studio를 사용하고 있으며 jni 빌드가 jniLibs 대신 libs에 복사되었습니다.
Luis

4
전체 세트가 필요하다는 마지막 메모는 저에게 중요했습니다. 그게 내 문제 였어, 고마워!
Ben Trengrove 2015 년

를 들어 7섹션 : 당신은 APK에서 변경 될 수 .so를 (가)가 장치에 설치 한 후 의미합니까? 그렇다면 시스템이 .so 파일을 망칠 가능성이 있습니까?
jayatubi

5
훌륭한! 내 아주 이상한 경우에는 타사 라이브러리 세트 (OpenCV- armeabi 폴더)를 사용하고 있었고 Gradle을 통해 다른 타사 라이브러리를 추가했을 때 해당 라이브러리가로드를 중지했습니다. 두 번째 라이브러리는 ARMv5 또는 6을 지원하지 않는 것으로 나타 났으며이를 포함함으로써 내 OpenCV 라이브러리가 보이지 않게되었습니다 ( 실제로는 존재 했지만 ). 전체 세트에 대한 귀하의 요점은 저에게 단서를주었습니다. armeabi 폴더의 이름을 바꾸고 armeabi-v7a 라고 부르면 문제가 해결되었습니다 (지금은 ARM 5 또는 6을 지원하지 않기 때문에 ...). 사악한 문제 !!
Mete

1
lib 파일 (* .so)을 저장할 위치를 찾는 또 다른 방법은 애플리케이션을 실행하고 다음을 사용하여 nativeLibraryDir을 인쇄하는 것입니다. System.out.println (getApplicationContext (). getApplicationInfo (). nativeLibraryDir), 디렉토리 이름도 ABI를 제공합니다.
David Rauca 2017 년

20

Gradle에서 모든 파일 폴더를 libs/

jniLibs.srcDirs = ['libs']

위의 라인을 추가 sourceSetsbuild.gradle파일은했다. 다른 어떤 것도 작동하지 않았습니다.


2
"sourceSets"는 build.gradle 파일에 있습니까?
Ashana.Jackol

12

Gradle을 사용하고 있습니까? 그렇다면 .so파일을 넣으십시오 .<project>/src/main/jniLibs/armeabi/

도움이되기를 바랍니다.


아니요, 저는 gradle을 사용하지 않습니다. eclipse + maven을 사용하고 있습니다
user842225

12

제 경우에는 gradle로 컴파일 소스를 제외하고 libs 경로를 설정해야합니다.

android {

    ...
    sourceSets {
        ...
        main.jni.srcDirs = []
        main.jniLibs.srcDirs = ['libs']
    }
....

이것은 나를 위해 해결되었고 armeabi-v7a 및 x86 폴더에 armeabi 파일을 추가했지만 필요한지 확실하지 않습니다.
dokam_scotland

8

이 오류의 원인은 앱과 연결된 네이티브 라이브러리간에 ABI가 일치하지 않기 때문입니다. 다시 말해, 귀하의 앱과 귀하의 앱 .so이 서로 다른 ABI를 타겟팅 하고 있습니다 .

최신 Android Studio 템플릿을 사용하여 앱을 만드는 경우 아마도를 타겟팅 arm64-v8a.so수 있지만 armeabi-v7a예를 들어 타겟팅 할 수 있습니다 .

이 문제를 해결하는 방법에는 두 가지가 있습니다.

  1. 앱에서 지원하는 각 ABI에 대한 네이티브 라이브러리를 빌드합니다.
  2. .so빌드 한 이전 ABI를 대상으로 앱을 변경합니다 .

선택 2는 더럽지 만 다음 항목에 더 관심이있을 것 같습니다.

앱 변경 build.gradle

android {
    defaultConfig {
        ...
        ndk {
            abiFilters 'armeabi-v7a'
        }
   }
}

내 앱이 이클립스에 있다면 어떨까요? 이 문제는 동일한 맞춤형 앱을 6에서 9로 마이그레이션 할 때 발생합니다.
Shadow

6

참고로,이 오류 메시지가 있었고 해결책은 라이브러리를 지정할 때 앞면에서 'lib'를, 끝에서 '.so'를 놓친다는 것입니다.

따라서 libmyfablib.so 파일이있는 경우 다음을 호출해야합니다.

   System.loadLibrary("myfablib"); // this loads the file 'libmyfablib.so' 

APK를 살펴보고, 설치 / 제거하고, 모든 종류의 복잡한 솔루션을 시도해 본 결과 내 얼굴 바로 앞에있는 간단한 문제를 볼 수 없었습니다!


그거였다. 알 수없는 이유로 Android는 패키지에 존재하더라도 파일 이름이 'lib'로 시작하지 않는 라이브러리를 설치하지 않습니다. 이동 그림 ...
조지 Y.

프로젝트에서 이것을 어디서 확인할 수 있습니까? 나는이 라인을 찾을 수있는 위치를 의미하는 System.loadLibrary코드에
aleksandrbel

감사. 이것은 도움이되었습니다!
Riskhan

5

이것은 Android 8 업데이트입니다.

이전 버전의 Android에서는 LoadLibrary 네이티브 공유 라이브러리 (예 : JNI를 통한 액세스 용)에 다양한 apk 설치 / 업그레이드 알고리즘을 기반으로 lib 폴더의 잠재적 인 디렉터리 경로 범위를 반복하도록 네이티브 코드를 고정 연결했습니다.

/data/data/<PackageName>/lib
/data/app-lib/<PackageName>-1/lib
/data/app-lib/<PackageName>-2/lib
/data/app/<PackageName>-1/lib
/data/app/<PackageName>-2/lib

이 접근 방식은 간단하며 Android 8에서는 작동하지 않습니다. https://developer.android.com/about/versions/oreo/android-8.0-changes.html 에서 "보안"변경의 일부로 이제 sourceDir을 사용해야 함을 알 수 있습니다.

"더 이상 APK가 이름이 -1 또는 -2로 끝나는 디렉토리에 있다고 가정 할 수 없습니다. 앱은 디렉토리 형식에 직접 의존하지 말고 sourceDir을 사용하여 디렉토리를 가져와야합니다."

수정, sourceDir은 기본 공유 라이브러리를 찾는 방법이 아닙니다. 같은 것을 사용하십시오. Android 4.4.4-> 8.0에서 테스트 됨

// Return Full path to the directory where native JNI libraries are stored.
private static String getNativeLibraryDir(Context context) {
    ApplicationInfo appInfo = context.getApplicationInfo();
    return appInfo.nativeLibraryDir;
}

4

포함 PREBUILT_SHARED_LIBRARY섹션 후에 라이브러리를 호출하십시오 .

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)
LOCAL_MODULE    := libcalculate
LOCAL_SRC_FILES := <PATH>/libcalculate.so
include $(PREBUILT_SHARED_LIBRARY)

#...

LOCAL_SHARED_LIBRARIES += libcalculate

최신 정보:

Java에서이 라이브러리를 사용하려면 공유 라이브러리로 컴파일해야합니다.

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)
LOCAL_MODULE    := libcalculate
LOCAL_SRC_FILES := <PATH>/libcalculate.so
include $(BUILD_SHARED_LIBRARY)

그리고 /vendor/lib디렉토리에 라이브러리를 배포해야합니다 .


섹션 끝에서만.
알렉스

2

이전 빌드를 사용하도록 ABI를 변경할 수 있습니다.

defaultConfig {
    ...

    ndk {
        abiFilters 'armeabi-v7a'
    }
    ...
}

또한 다음 행을 gradle.properties다음 에 추가하여 지원 중단 된 NDK를 사용해야합니다 .

android.useDeprecatedNdk=true

0

모든 지원을 추가하십시오

app / build.gradle

ndk {
        moduleName "serial_port"
        ldLibs "log", "z", "m"
        abiFilters "arm64-v8a","armeabi", "armeabi-v7a", "x86","x86_64","mips","mips64"
}

app \ src \ jni \ Application.mk

APP_ABI := arm64-v8a armeabi armeabi-v7a x86 x86_64 mips mips64

1
무엇을해야하는지 좀 더 구체적으로 말씀해 주시겠습니까?
EFrank

프로젝트의 .so 파일. arm64-v8a armeabi armeabi-v7a x86 x86_64 mips mips64를 지원해야합니다. 내가 그랬을 때 잘 작동합니다.
사자耿

-1

내 경험상 armeabi-v7a 모바일에서 armeabi 및 armeabi-v7a 디렉토리가 모두 apk에있을 때 armeabi 디렉토리의 .so 파일은 링크되지 않지만 armeabi의 .so 파일은 armeabi-v7a가없는 경우 동일한 armeabi-v7a 모바일.


-1

실제로, 당신은 단지에 .so는 파일을 넣을 수 없습니다 /libs/armeabi/와 함께로드 System.loadLibrary. Android.mk 파일을 만들고 .so 파일을 소스로 지정하는 사전 빌드 된 모듈을 선언해야합니다.

이렇게하려면 .so 파일과 Android.mk 파일을 jni폴더에 넣으십시오 . Android.mk는 다음과 같아야합니다.

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)
LOCAL_MODULE    := libcalculate
LOCAL_SRC_FILES := libcalculate.so
include $(PREBUILT_SHARED_LIBRARY)

출처 : 사전 빌드에 대한 Android NDK 문서

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.