System.loadLibrary (…) konnte in meinem Fall keine native Bibliothek finden

90

Ich möchte eine vorhandene native Bibliothek aus einem anderen Android-Projekt verwenden, daher habe ich die von NDK erstellte Bibliothek ( libcalculate.so ) einfach in mein neues Android-Projekt kopiert . In meinem neuen Android-Projekt habe ich einen Ordner erstellt libs/armeabi/und libcalculate.so dort abgelegt . Es gibt keinen jni / Ordner. Mein Testgerät verfügt über eine ARM-Architektur.

In meinem Java-Code lade ich die Bibliothek durch:

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

Beim Ausführen meines neuen Android-Projekts wurde folgende Fehlermeldung angezeigt:

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

Wie der Fehler sagt, befindet sich die kopierte native Bibliothek nicht in / verdor / lib oder / system / lib. Wie kann dieses Problem in meinem Fall behoben werden?

(Ich habe das apk-Paket entpackt, unter lib / gibt es libcalculate.so)

==== UPDATE =====

Ich habe auch versucht, einen jni / -Ordner unter dem Projektstamm zu erstellen und eine Android.mk-Datei unter jni / hinzuzufügen. Der Inhalt von Android.mk ist:

LOCAL_PATH := $(call my-dir)

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

Dann habe ich unter Projektstamm ndk-build ausgeführt. Danach werden die Verzeichnisse armeabi / und armeabi-v7a / von ndk-build generiert (mit libcalculate.so im Ordner).

Dann führe ich meinen Maven aus, um das Projekt erfolgreich zu erstellen. Im endgültigen apk-Paket gibt es:

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

Aber wenn ich meine App starte, wird der gleiche Fehler ausgelöst:

java.lang.UnsatisfiedLinkError:  ...
nativeLibraryDirectories=[/vendor/lib, /system/lib]]] couldn't find "libcalculate.so"
user842225
quelle
3
Sie stellen die Bibliothek direkt unter libs/? Sie müssen wahrscheinlich ein Unterverzeichnis pro Ziel-ABI erstellen, das Sie unterstützen möchten (armeabi, armeabi-v7a, x86, mips usw.) und die entsprechende .so-Datei in jedem Unterverzeichnis ablegen (dh die für armeabi erstellte .so-Datei wird eingegeben) libs/armeabi/. etc).
Michael
@ Michael, ich habe gerade verpasst, dass ich es in meinem Beitrag tatsächlich unter libs / armeabi /
user842225
Überprüfen Sie, ob libcalculate.so tatsächlich vom Verpackungsprozess erfasst wird - versuchen Sie es beispielsweise unzip -l package.apkoder benennen Sie die apk in .zip um und öffnen Sie sie mit einer Anwendung. Wenn es nicht vorhanden ist, stimmt etwas beim Packen nicht (hat Ihre IDE bemerkt, dass der Ordner vorhanden ist, müssen Sie das Projekt aktualisieren?).
Mstorsjo
@mstorsjo, ich habe das apk-Paket entpackt, unter lib / gibt es libcalculate.so
user842225
1
Sie benötigen kein Android.mk oder kompilierungsbezogene Dateien. Legen Sie die so-Dateien einfach in den entsprechenden Unterverzeichnissen für jniLibs wie hier ab: github.com/Ph1b/MaterialAudiobookPlayer/tree/master/audiobook/…
Paul Woitaschek

Antworten:

173

Um die Ursache zu ermitteln (und möglicherweise Ihr Problem gleichzeitig zu lösen), können Sie Folgendes tun:

  1. Entfernen Sie den Ordner jni und alle .mk- Dateien. Sie benötigen diese und das NDK nicht, wenn Sie nichts kompilieren.

  2. Kopieren Sie Ihre libcalculate.soDatei hinein <project>/libs/(armeabi|armeabi-v7a|x86|...). Wenn Sie Android Studio verwenden, ist dies der Fall <project>/app/src/main/jniLibs/(armeabi|armeabi-v7a|x86|...), aber ich sehe, dass Sie Eclipse verwenden.

  3. Erstellen Sie Ihre APK und öffnen Sie sie als Zip-Datei , um zu überprüfen, ob Ihrelibcalculate.so Datei in lib / (armeabi | armeabi-v7a | x86 | ...) befindet .

  4. Entfernen und installieren Sie Ihre Anwendung

  5. Führen Sie dumpsys package packages | aus grep yourpackagename , um den nativeLibraryPath oder zu erhalten legacyNativeLibraryDir Ihrer Anwendung abzurufen .

  6. Führen Sie ls auf dem nativeLibraryPath aus, den Sie hatten oder auf dem legacyNativeLibraryDir / armeabi , um zu überprüfen, ob Ihre libcalculate.so tatsächlich vorhanden ist.

  7. Wenn es dort ist, überprüfen Sie, ob es nicht von Ihrem Original geändert wurde libcalculate.so- Datei geändert wurde : Wird es gegen die richtige Architektur kompiliert, enthält es die erwarteten Symbole, fehlen Abhängigkeiten. Sie können libcalculate.so mit readelf analysieren.

Um Schritt 5-7 zu überprüfen, können Sie meine Anwendung anstelle von Befehlszeilen verwenden und sich selbst lesen: Native Libs Monitor

PS: Es ist leicht zu verwechseln, wo .so-Dateien standardmäßig abgelegt oder generiert werden sollen. Hier eine Zusammenfassung:

  • libs / CPU_ABI in einem Eclipse-Projekt

  • jniLibs / CPU_ABI in einem Android Studio-Projekt

  • jni / CPU_ABI in einem AAR

  • lib / CPU_ABI in der endgültigen APK

  • innerhalb des nativeLibraryPath der App auf einem <5.0-Gerät und innerhalb der App LegacyNativeLibraryDir / CPU_ARCH auf einem> = 5.0-Gerät.

Wobei CPU_ABI eines der folgenden Elemente ist: armeabi, armeabi-v7a, arm64-v8a, x86, x86_64, mips, mips64 . Abhängig davon, auf welche Architekturen Sie abzielen und für welche Ihre Bibliotheken kompiliert wurden.

Beachten Sie auch, dass Bibliotheken nicht zwischen CPU_ABI-Verzeichnissen gemischt werden: Sie benötigen den vollständigen Satz Ihrer Verwendungszwecke. Eine Bibliothek im Ordner armeabi wird nicht auf einem armeabi-v7a- Gerät installiert , wenn sich Bibliotheken im Armeabi befinden -v7a Ordner aus der APK.

ph0b
quelle
3
Super Mann, danke! Ich verwende Android Studio und meine jni-Builds wurden anstelle von jniLibs in libs kopiert.
Luis
4
Diese letzte Anmerkung über die Notwendigkeit des vollständigen Satzes war für mich von entscheidender Bedeutung. Das war mein Problem, danke!
Ben Trengrove
Für den 7Abschnitt: Meinen Sie, dass die .so-Datei möglicherweise von der APK geändert wird, nachdem sie auf dem Gerät installiert wurde? Wenn ja, besteht die Möglichkeit, dass das System die .so-Datei ruiniert?
Jayatubi
5
Wunderbar! In meinem sehr seltsamen Fall habe ich einen Satz von Bibliotheken von Drittanbietern (OpenCV - im armeabi- Ordner) verwendet, und diese Bibliotheken wurden nicht mehr geladen, als ich über Gradle eine andere Bibliothek von Drittanbietern hinzufügte. Es stellt sich heraus, dass die zweite Bibliothek ARMv5 oder 6 nicht unterstützt, und durch das Einschließen wurden meine OpenCV-Bibliotheken unsichtbar (obwohl sie tatsächlich vorhanden waren ). Ihr Punkt bezüglich des vollständigen Satzes gab mir den Hinweis - das Umbenennen des armeabi-Ordners und das Aufrufen von armeabi-v7a haben das Problem behoben (da ich ARM 5 oder 6 jetzt nicht unterstütze ...). Böses Problem !!
Mete
1
Eine andere Möglichkeit, um herauszufinden, wo Sie Ihre lib-Datei (* .so) ablegen können, besteht darin, Ihre Anwendung auszuführen und das nativeLibraryDir zu drucken. Dabei wird Folgendes verwendet: System.out.println (getApplicationContext (). GetApplicationInfo (). NativeLibraryDir). Der Name des Verzeichnisses wird ebenfalls angezeigt versorgen Sie mit dem ABI.
David Rauca
19

In gradle nach dem Kopieren aller Dateiordner in libs/

jniLibs.srcDirs = ['libs']

Das Hinzufügen der obigen Zeile sourceSetsin build.gradleDatei gearbeitet. Sonst hat nichts funktioniert.

Mukund Muralikrishnan
quelle
2
Wo befindet sich "sourceSets" in der Datei build.gradle?
Ashana.Jackol
12

Verwenden Sie Gradle? Wenn ja, setzen Sie die.so Datei ein<project>/src/main/jniLibs/armeabi/

Ich hoffe, es hilft.

Assaf Gamliel
quelle
nein, ich benutze nicht gradle, ich benutze eclipse + maven
user842225
12

In meinem Fall muss ich das Kompilieren von Quellen nach Gradle ausschließen und den libs-Pfad festlegen

android {

    ...
    sourceSets {
        ...
        main.jni.srcDirs = []
        main.jniLibs.srcDirs = ['libs']
    }
....
Dawid Drozd
quelle
Dies löste sich auch für mich und ich fügte die Dateien von armeabi in den Ordnern armeabi-v7a und x86 hinzu, bin mir aber nicht sicher, ob es notwendig war.
dokam_scotland
8

Der Grund für diesen Fehler liegt darin, dass die ABI zwischen Ihrer App und der nativen Bibliothek, mit der Sie verknüpft haben, nicht übereinstimmt. Mit anderen Worten, Ihre App und Ihre .sozielen auf unterschiedliche ABI ab.

Wenn Sie Ihre App mit den neuesten Android Studio-Vorlagen erstellen, richtet sie sich wahrscheinlich an die, arm64-v8aaber .somöglicherweise an Ihre armeabi-v7a.

Es gibt zwei Möglichkeiten, um dieses Problem zu lösen:

  1. Erstellen Sie Ihre nativen Bibliotheken für jedes ABI, das Ihre App unterstützt.
  2. Ändern Sie Ihre App so, dass sie auf ältere ABI abzielt, .sogegen die Sie gebaut haben.

Wahl 2 ist schmutzig, aber ich denke, Sie haben wahrscheinlich mehr Interesse an:

Ändern Sie Ihre App build.gradle

android {
    defaultConfig {
        ...
        ndk {
            abiFilters 'armeabi-v7a'
        }
   }
}
wdanxna
quelle
Was ist, wenn meine App in Eclipse ist? Dieses Problem tritt auf, wenn ich dieselbe angepasste App von 6 auf 9 migriere.
Shadow
6

Als Referenz hatte ich diese Fehlermeldung und die Lösung war, dass Sie, wenn Sie die Bibliothek angeben, die 'lib' von vorne und die '.so' am Ende vermissen.

Wenn Sie also eine Datei libmyfablib.so haben, müssen Sie Folgendes aufrufen:

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

Nachdem ich in der apk nachgesehen, installiert / deinstalliert und alle möglichen komplexen Lösungen ausprobiert hatte, konnte ich das einfache Problem nicht erkennen, das direkt vor meinem Gesicht lag!

Andy Krouwel
quelle
Das war's. Aus einem unbekannten Grund installiert Android keine Bibliotheken, deren Dateiname nicht mit 'lib' beginnt, selbst wenn sie im Paket vorhanden sind. Go figure ...
George Y.
Wo kann ich das im Projekt überprüfen? Ich meine, wo finde ich diese Zeile System.loadLibraryim Code
aleksandrbel
Vielen Dank. Das hat geholfen!
Riskhan
5

Dies ist ein Android 8-Update.

In einer früheren Version von Android habe ich für native LoadLibrary-Shared-Libraries (z. B. für den Zugriff über JNI) meinen nativen Code fest verdrahtet, um eine Reihe potenzieller Verzeichnispfade für den lib-Ordner zu durchlaufen, basierend auf den verschiedenen apk-Installations- / Upgrade-Algorithmen:

/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

Dieser Ansatz ist hokey und funktioniert nicht für Android 8; Unter https://developer.android.com/about/versions/oreo/android-8.0-changes.html sehen Sie, dass Sie im Rahmen der "Sicherheits" -Änderungen jetzt sourceDir verwenden müssen:

"Sie können nicht mehr davon ausgehen, dass sich APKs in Verzeichnissen befinden, deren Namen auf -1 oder -2 enden. Apps sollten sourceDir verwenden, um das Verzeichnis abzurufen, und sich nicht direkt auf das Verzeichnisformat verlassen."

Korrektur, sourceDir ist nicht der Weg, um Ihre nativen gemeinsam genutzten Bibliotheken zu finden. benutze so etwas wie. Getestet für 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;
}
AlgebraWinter
quelle
4

Versuchen Sie, Ihre Bibliothek nach dem Include- PREBUILT_SHARED_LIBRARYAbschnitt aufzurufen :

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

Aktualisieren:

Wenn Sie diese Bibliothek in Java verwenden möchten, müssen Sie sie als gemeinsam genutzte Bibliothek kompilieren

LOCAL_PATH := $(call my-dir)

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

Und Sie müssen die Bibliothek im /vendor/libVerzeichnis bereitstellen .

Alex
quelle
Nur am Ende des Abschnitts.
Alex
2

Sie können ABI einfach ändern, um ältere Builds zu verwenden:

defaultConfig {
    ...

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

Sie sollten auch veraltetes NDK verwenden, indem Sie diese Zeile hinzufügen zu gradle.properties:

android.useDeprecatedNdk=true
Rezam
quelle
0

Bitte fügen Sie alle Unterstützung hinzu

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
Löwe 耿
quelle
1
Könnten Sie bitte genauer sagen, was zu tun ist?
EFrank
Die .so-Datei in Ihrem Projekt. Sie sollten arm64-v8a armeabi armeabi-v7a x86 x86_64 mips mips64 unterstützen. Als ich das gemacht habe, hat es gut funktioniert.
Löwe 耿
-1

Nach meiner Erfahrung werden in einem armeabi-v7a-Handy, wenn sowohl armeabi- als auch armeabi-v7a-Verzeichnisse in der apk vorhanden sind, die .so-Dateien im armeabi-Verzeichnis nicht verknüpft, obwohl die .so-Dateien in armeabi im dasselbe armeabi-v7a-Handy, wenn armeabi-v7a nicht vorhanden ist.

Loopscn
quelle
-1

Eigentlich kann man nicht einfach eine .so-Datei in die Datei einfügen /libs/armeabi/und mit laden System.loadLibrary. Sie müssen eine Android.mk-Datei erstellen und ein vorgefertigtes Modul deklarieren, in dem Sie Ihre .so-Datei als Quelle angeben.

Legen Sie dazu Ihre .so-Datei und die Android.mk-Datei in den jniOrdner. Dein Android.mk sollte ungefähr so ​​aussehen:

LOCAL_PATH := $(call my-dir)

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

Quelle: Android NDK-Dokumentation zu vorgefertigten

Yannshu
quelle