System.loadLibrary (…) ไม่พบไลบรารีเนทีฟในกรณีของฉัน


93

ฉันต้องการใช้ไลบรารีเนทีฟที่มีอยู่จากโปรเจ็กต์ Android อื่นดังนั้นฉันเพิ่งคัดลอกไลบรารีที่สร้างขึ้น NDK ( libcalculate.so ) ไปยังโปรเจ็กต์ Android ใหม่ของฉัน ในโครงการ Android ใหม่ของฉันฉันสร้างโฟลเดอร์libs/armeabi/และวางlibcalculate.soไว้ที่นั่น นอกจากนี้ไม่มี JNI / โฟลเดอร์ อุปกรณ์ทดสอบของฉันมีสถาปัตยกรรม ARM

ในรหัส java ของฉันฉันโหลดไลบรารีโดย:

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

เมื่อฉันเรียกใช้โครงการ Android ใหม่ฉันได้รับข้อผิดพลาด:

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

ดังนั้นตามที่ระบุข้อผิดพลาดไลบรารีเนทีฟที่คัดลอกไม่ได้อยู่ใน / verdor / lib หรือ / system / lib จะแก้ไขปัญหานี้ในกรณีของฉันได้อย่างไร

(ฉันคลายซิปแพ็คเกจ apk ภายใต้ lib / มี libcalculate.so)

==== อัปเดต =====

ฉันพยายามสร้าง jni / โฟลเดอร์ภายใต้โปรเจ็กต์รูทและเพิ่มไฟล์ 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)

จากนั้นภายใต้โปรเจ็กต์รูทฉันดำเนินการ 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 ที่เหมาะสมในแต่ละไดเร็กทอรีย่อย (เช่นไฟล์. so ที่สร้างขึ้นสำหรับ armeabi จะเข้าlibs/armeabi/, ฯลฯ )
Michael

@ ไมเคิลฉันพลาดที่โพสต์ของฉันจริง ๆ แล้วฉันวางไว้ใต้ libs / armeabi /
user842225

ตรวจสอบว่า libcalculate.so ได้รับจริงจากกระบวนการบรรจุภัณฑ์ - ลองเช่นunzip -l package.apkหรือเปลี่ยนชื่อ apk เป็น. zip และเปิดด้วยแอปพลิเคชันบางอย่าง หากไม่มีแสดงว่ามีบางอย่างผิดปกติกับบรรจุภัณฑ์ (IDE ของคุณสังเกตเห็นว่ามีโฟลเดอร์อยู่หรือไม่คุณต้องรีเฟรชโครงการหรือไม่)
mstorsjo

@mstorsjo ฉันคลายซิปแพ็คเกจ apk ภายใต้ lib / มี libcalculate.so
user842225

1
คุณไม่จำเป็นต้องมี Android.mk หรือไฟล์ที่เกี่ยวข้องกับการคอมไพล์ เพียงใส่ไฟล์ so ในไดเร็กทอรีย่อยตามไปยัง jniLibs เช่นที่นี่: github.com/Ph1b/MaterialAudiobookPlayer/tree/master/audiobook/…
Paul Woitaschek

คำตอบ:


179

หากต้องการทราบสาเหตุ (และอาจแก้ปัญหาของคุณได้ในเวลาเดียวกัน) นี่คือสิ่งที่คุณสามารถทำได้:

  1. ลบโฟลเดอร์jni และไฟล์. mkทั้งหมด คุณไม่ต้องการสิ่งเหล่านี้หรือ NDK หากคุณไม่ได้รวบรวมอะไรเลย

  2. คัดลอกในแฟ้มlibcalculate.so <project>/libs/(armeabi|armeabi-v7a|x86|...)ตอนใช้ Android Studio มันเป็น<project>/app/src/main/jniLibs/(armeabi|armeabi-v7a|x86|...)แต่ฉันเห็นว่าคุณใช้ eclipse

  3. สร้าง APK ของคุณและเปิดเป็นไฟล์ซิปเพื่อตรวจสอบว่าคุณlibcalculate.soไฟล์ที่อยู่ภายในlib / (armeabi | armeabi-v7a | x 86 | ... )

  4. ลบและติดตั้งแอปพลิเคชันของคุณ

  5. เรียกใช้แพ็คเกจแพ็คเกจ dumpsys | grep yourpackagenameเพื่อรับnativeLibraryPathหรือlegacyNativeLibraryDirของแอปพลิเคชันของคุณ

  6. รันlsบนnativeLibraryPath ที่คุณมีหรือบนlegacyNativeLibraryDir / armeabiเพื่อตรวจสอบว่า libcalculate.so ของคุณอยู่ที่นั่นจริงหรือไม่

  7. หากมีอยู่ให้ตรวจสอบว่าไม่มีการเปลี่ยนแปลงจากไฟล์libcalculate.soดั้งเดิมของคุณหรือไม่: คอมไพล์กับสถาปัตยกรรมที่ถูกต้องมีสัญลักษณ์ที่คาดไว้หรือไม่มีการอ้างอิงที่ขาดหายไปหรือไม่ คุณสามารถวิเคราะห์ libcalculate.so โดยใช้ readelf

ในการตรวจสอบขั้นตอนที่ 5-7 คุณสามารถใช้แอปพลิเคชันของฉันแทนบรรทัดคำสั่งและอ่านด้วยตัวเอง: Native Libs Monitor

PS: มันง่ายที่จะสับสนว่าไฟล์. ดังนั้นควรจะใส่หรือสร้างโดยค่าเริ่มต้นนี่คือบทสรุป:

  • libs / CPU_ABIภายในโปรเจ็กต์ eclipse

  • jniLibs / CPU_ABIภายในโครงการ Android Studio

  • jni / CPU_ABIภายใน AAR

  • lib / CPU_ABIภายใน APK สุดท้าย

  • ภายในnativeLibraryPathของแอปบนอุปกรณ์ <5.0 และภายในlegacyNativeLibraryDir / CPU_ARCHของแอปบนอุปกรณ์> = 5.0

ที่ไหนCPU_ABIใด ๆ ของ: armeabi, armeabi-v7a, arm64-V8A, x86, x86_64, MIPS, MIPS64 ขึ้นอยู่กับสถาปัตยกรรมที่คุณกำหนดเป้าหมายและ libs ของคุณได้รับการรวบรวม

โปรดทราบด้วยว่า libs ไม่ได้ผสมกันระหว่างไดเรกทอรี CPU_ABI: คุณต้องมีชุดเต็มของสิ่งที่คุณกำลังใช้งาน lib ที่อยู่ใน โฟลเดอร์armeabiจะไม่ถูกติดตั้งบนอุปกรณ์armeabi-v7aหากมี libs ใด ๆ อยู่ในarmeabi -v7aโฟลเดอร์จาก APK


3
คนน่ากลัวขอบคุณ! ฉันใช้ Android Studio และงานสร้าง jni ของฉันถูกคัดลอกไปยัง libs แทน jniLibs
ลุย

4
บันทึกสุดท้ายเกี่ยวกับความต้องการชุดเต็มเป็นสิ่งสำคัญสำหรับฉัน นั่นคือปัญหาของฉันขอบคุณ!
Ben Trengrove

สำหรับ7ส่วนนี้: คุณหมายถึงว่าอาจมีการเปลี่ยนแปลงจาก APK หลังจากติดตั้งบนอุปกรณ์หรือไม่ ถ้าเป็นเช่นนั้นจะมีโอกาสที่ระบบอาจทำลายไฟล์. 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

21

ใน gradle หลังจากคัดลอกโฟลเดอร์ไฟล์ทั้งหมดไปที่ libs/

jniLibs.srcDirs = ['libs']

การเพิ่มบรรทัดด้านบนsourceSetsในbuild.gradleไฟล์ใช้งานได้ ไม่มีอะไรอื่นที่ใช้งานได้


2
มี "sourceSets" อยู่ในไฟล์ build.gradle หรือไม่
Ashana.Jackol

@ Ashana. Jackol ใน build.gradle ของคุณ
olajide

13

ในกรณีของฉันฉันต้องแยกซอร์สการคอมไพล์โดยการไล่ระดับและตั้งค่าเส้นทาง libs

android {

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

สิ่งนี้แก้ไขให้ฉันเช่นกันและฉันได้เพิ่มไฟล์ของ armeabi ในโฟลเดอร์ armeabi-v7a และ x86 แต่ฉันไม่แน่ใจว่าจำเป็นหรือไม่
dokam_scotland

12

คุณใช้ gradle หรือไม่? ถ้าเป็นเช่นนั้นให้ใส่.soไฟล์<project>/src/main/jniLibs/armeabi/

ฉันหวังว่ามันจะช่วยได้


ไม่ฉันไม่ได้ใช้ gradle ฉันใช้ eclipse + maven
user842225

8

สาเหตุของข้อผิดพลาดนี้เป็นเพราะ ABI ไม่ตรงกันระหว่างแอปของคุณกับไลบรารีดั้งเดิมที่คุณเชื่อมโยง อีกคำหนึ่งแอปของคุณและของคุณ.soกำหนดเป้าหมาย ABI ที่แตกต่างกัน

หากคุณสร้างแอปของคุณโดยใช้เทมเพลต Android Studio ล่าสุดแอปอาจกำหนดเป้าหมายarm64-v8aแต่คุณ.soอาจกำหนดเป้าหมายarmeabi-v7aเช่น

มี 2 ​​วิธีในการแก้ปัญหานี้:

  1. สร้างไลบรารีดั้งเดิมของคุณสำหรับแต่ละ ABI ที่แอปของคุณรองรับ
  2. เปลี่ยนแอปของคุณเพื่อกำหนดเป้าหมาย ABI รุ่นเก่าที่คุณ.soสร้างขึ้น

ตัวเลือก 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" แม้ว่าจะมีอยู่ในแพ็คเกจก็ตาม Go figure ...
George Y.

ฉันจะตรวจสอบสิ่งนี้ได้ที่ไหนในโครงการ? ฉันหมายถึงว่าฉันจะหาบรรทัดนี้ได้ที่ไหนSystem.loadLibraryในรหัส
aleksandrbel

ขอบคุณ. สิ่งนี้ช่วยได้!
Riskhan

6

นี่คือการอัปเดต Android 8

ใน Android เวอร์ชันก่อนหน้าไปยังไลบรารีที่แบ่งใช้แบบเนทีฟของ LoadLibrary (สำหรับการเข้าถึงผ่าน JNI เป็นต้น) ฉันต่อสายรหัสเนทีฟของฉันอย่างหนักเพื่อวนซ้ำผ่านช่วงของเส้นทางไดเรกทอรีที่เป็นไปได้สำหรับโฟลเดอร์ lib โดยอิงตามอัลกอริทึมการติดตั้ง / อัปเกรด apk ต่างๆ:

/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ไดเร็กทอรี


เฉพาะในส่วนท้ายของส่วน
Alex

2

คุณสามารถเปลี่ยน ABI เพื่อใช้งานรุ่นเก่าได้:

defaultConfig {
    ...

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

คุณควรใช้ NDK ที่เลิกใช้แล้วโดยเพิ่มบรรทัดนี้ในgradle.properties:

android.useDeprecatedNdk=true

0

จริงๆแล้วคุณไม่สามารถใส่ไฟล์. 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 เกี่ยวกับการสร้างไว้ล่วงหน้า


0

กรุณาเพิ่ม suport ทั้งหมด

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 mobile เมื่อทั้งไดเรกทอรี armeabi และ armeabi-v7a อยู่ใน apk ไฟล์. so ในไดเรกทอรี armeabi จะไม่ถูกเชื่อมโยงแม้ว่าไฟล์. so ใน armeabi จะเชื่อมโยงใน armeabi-v7a มือถือเดียวกันหากไม่มี armeabi-v7a

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.