System.loadLibrary (…) benim durumumda yerel kitaplığı bulamadı


91

Başka bir Android projesinden mevcut bir yerel kitaplığı kullanmak istiyorum , bu nedenle NDK yerleşik kitaplığını ( libcalculate.so ) yeni Android projeme kopyaladım . Yeni Android projemde bir klasör oluşturdum libs/armeabi/ve libcalculate.so dosyasını oraya koydum . Orada hiçbir jni / klasör. Test cihazım ARM mimarisine sahip.

Java kodumda kitaplığı şu şekilde yüklüyorum:

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

Yeni android projemi çalıştırdığımda hata alıyorum:

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

Öyleyse, hatanın dediği gibi, kopyalanan yerel kitaplık / verdor / lib veya / system / lib içinde değil, benim durumumda bu sorunu nasıl çözebilirim?

(Apk paketini lib altında açtım / libcalculate.so var)

==== GÜNCELLEME =====

Ayrıca proje kökü altında bir jni / klasörü oluşturmaya ve jni / altına bir Android.mk dosyası eklemeye çalıştım. Android.mk'nin içeriği:

LOCAL_PATH := $(call my-dir)

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

Ardından, proje kökü altında ndk-build çalıştırdım. Bundan sonra, armeabi / ve armeabi-v7a / dizinleri ndk-build tarafından oluşturulur (klasörün içinde libcalculate.so ile).

Daha sonra projemi başarıyla inşa ettim. Son apk paketinde şunlar bulunur:

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

Ancak uygulamamı çalıştırdığımda aynı hata oluşuyor:

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

3
Kütüphaneyi doğrudan altına libs/mı koydunuz ? Muhtemelen desteklemek istediğiniz hedef ABI başına bir alt dizin oluşturmanız (armeabi, armeabi-v7a, x86, mips, vb.) Ve her alt dizine uygun .so dosyasını yerleştirmeniz gerekir (yani armeabi için oluşturulmuş .so dosyası girilir libs/armeabi/, vb).
Michael

@Michael, yazımda bunu kaçırdım, aslında libs / armeabi /
user842225

Libcalculate.so'nun gerçekten paketleme işlemi tarafından alındığını kontrol edin - örneğin deneyin unzip -l package.apkveya apk'yi .zip olarak yeniden adlandırın ve bir uygulamayla açın. Eğer yoksa, paketlemede bir sorun var (IDE'niz klasörün orada olduğunu fark etti mi, projeyi yenilemeniz gerekiyor mu?).
mstorsjo

@mstorsjo, apk paketini lib altında açtım / libcalculate.so var
user842225

1
Android.mk veya derlemeyle ilgili herhangi bir dosyaya sahip olmanız gerekmez. Sadece bu kadar dosyaları kendi alt dizinlerine aşağıdaki gibi jniLibs'e koyun
Paul Woitaschek

Yanıtlar:


178

Temel nedeni (ve belki de sorununuzu aynı anda çözmek) için şunları yapabilirsiniz:

  1. Jni klasörünü ve tüm .mk dosyalarını kaldırın . Hiçbir şey derlemiyorsanız bunlara veya NDK'ya ihtiyacınız yoktur.

  2. libcalculate.soDosyanızı içine kopyalayın <project>/libs/(armeabi|armeabi-v7a|x86|...). Android Studio'yu kullanırken, öyle <project>/app/src/main/jniLibs/(armeabi|armeabi-v7a|x86|...), ancak tutulması kullandığınızı görüyorum.

  3. APK'nızı oluşturun ve dosyanızın lib / (armeabi | armeabi-v7a | x86 | ...) içinde olup olmadığını kontrol etmek için bir zip dosyası olarak açın .libcalculate.so

  4. Uygulamanızı kaldırın ve yükleyin

  5. Dumpsys paket paketlerini çalıştırın | Uygulamanızın nativeLibraryPath veya legacyNativeLibraryDir dosyasını almak için paketinizin adını grep .

  6. Run ls üzerinde nativeLibraryPath yaşadığınız veya üzerinde legacyNativeLibraryDir / armeabi sizin libcalculate.so gerçekten orada olup olmadığını kontrol etmek.

  7. Varsa, orijinal libcalculate.so dosyanızdan değiştirilip değiştirilmediğini kontrol edin : doğru mimariye karşı derlenmiş mi, beklenen sembolleri içeriyor mu, eksik bağımlılıklar var mı? Libcalculate.so dosyasını readelf kullanarak analiz edebilirsiniz.

Adım 5-7'yi kontrol etmek için komut satırları yerine uygulamamı kullanabilir ve kendinizi okuyabilirsiniz: Native Libs Monitor

Not: .so dosyalarının varsayılan olarak nereye yerleştirilmesi veya oluşturulması gerektiği konusunda kafa karıştırmak kolaydır, işte bir özet:

  • bir tutulma projesi içinde libs / CPU_ABI

  • jniLibs / CPU_ABI bir Android Studio projesi içinde

  • jni / CPU_ABI bir AAR içinde

  • Son APK içinde lib / CPU_ABI

  • Uygulamanın içindeki nativeLibraryPath bir üzerinde <5.0 cihaz ve uygulamanın iç legacyNativeLibraryDir / CPU_ARCH bir üzerinde> = 5.0 cihazdan.

Nerede CPU_ABI : herhangi biri armeabi, armeabi-v7a, arm64-V8A, x86, x86_64, mips, mips64 . Hangi mimarileri hedeflediğinize ve kitaplıklarınızın derlendiğine bağlı olarak.

Ayrıca, CPU_ABI dizinleri arasında kitaplıkların karıştırılmadığını da unutmayın: Kullandığınız şeyin tam setine ihtiyacınız var, armeabi klasörünün içindeki bir kitaplık , armeabi içinde herhangi bir kitaplık varsa armeabi-v7a aygıtına yüklenmez APK'deki -v7a klasörü.


3
Harika adam, teşekkürler! Android Studio kullanıyorum ve jni derlemelerim jniLibs yerine lib'lere kopyalanıyordu.
Luis

4
Tam setin ihtiyaç duyulmasıyla ilgili son not benim için çok önemliydi. Bu benim sorunumdu, teşekkürler!
Ben Trengrove

İçin 7bölüm: Eğer APK'nızdan değişmiş olabilir .bu o cihazda yüklü sonra demek? Eğer öyleyse, sistemin .so dosyasını bozma şansı olur mu?
jayatubi

5
Olağanüstü! Çok garip durumumda, bir 3. parti kütüphane seti kullanıyordum (OpenCV - armeabi klasöründe) ve Gradle aracılığıyla farklı bir 3. parti kütüphane eklediğimde bu kütüphanelerin yüklenmesi durdu. İkinci kitaplığın ARMv5 veya 6'yı desteklemediği ortaya çıktı ve onu dahil ederek OpenCV kitaplıklarım görünmez hale geldi ( gerçekte orada olsalar bile ). Tam set hakkındaki düşünceniz bana ipucu verdi - armeabi klasörünü yeniden adlandırmak ve armeabi-v7a olarak adlandırmak sorunu çözdü (çünkü artık ARM 5 veya 6'yı desteklemiyorum ...). Kötü sorun !!
Mete

1
Kitaplık dosyanızı (* .so) nereye koyacağınızı bulmanın başka bir yolu da uygulamanızı çalıştırmak ve nativeLibraryDir'i şu şekilde yazdırmaktır: System.out.println (getApplicationContext (). GetApplicationInfo (). NativeLibraryDir), dizinin adı da size ABI'yi sağlar.
David Rauca

20

Gradle'da, tüm dosya klasörlerini kopyaladıktan sonra libs/

jniLibs.srcDirs = ['libs']

Yukarıdaki satır ekleme sourceSetsde build.gradledosyaya çalıştı. Başka hiçbir şey işe yaramadı.


2
build.gradle dosyasında bulunan "sourceSets" nedir?
Ashana.Jackol

12

Gradle kullanıyor musun? Eğer öyleyse .sodosyayı koyun<project>/src/main/jniLibs/armeabi/

Umut ediyorum bu yardım eder.


hayır, gradle kullanmıyorum, eclipse + maven kullanıyorum
user842225

12

Benim durumumda, derleme kaynaklarını gradle ile hariç tutmalı ve libs yolunu ayarlamalıyım

android {

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

bu benim için de çözüldü ve armeabi dosyalarını armeabi-v7a ve x86 klasörlerine ekledim ancak gerekli olup olmadığından emin değilim.
dokam_scotland

8

Bu hatanın nedeni, uygulamanız ile bağlantı kurduğunuz yerel kitaplık arasında ABI uyuşmazlığı olmasıdır. Başka bir deyişle, uygulamanız ve sizin .sofarklı ABI'yı hedefliyor.

Uygulamanızı en son Android Studio şablonlarını kullanarak oluşturursanız, muhtemelen hedefliyor arm64-v8aancak sizin .sohedefiniz armeabi-v7aörneğin

Bu sorunu çözmenin 2 yolu var:

  1. Uygulamanızın desteklediği her ABI için yerel kitaplıklarınızı oluşturun.
  2. uygulamanızı, oluşturduğunuz eski ABI'yı hedefleyecek şekilde değiştirin .so.

2. Seçenek kirli ama muhtemelen şunlarla daha çok ilgilendiğinizi düşünüyorum:

uygulamanızı değiştirin build.gradle

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

Ya benim uygulamam tutulmaktaysa? Bu sorun, aynı özelleştirilmiş uygulamayı 6'dan 9'a
Gölge

6

Referans için, bu hata mesajını aldım ve çözüm, kitaplığı belirlediğinizde önden 'lib' ve sondan '.so' karakterini kaçırmanızdı.

Öyleyse, bir libmyfablib.so dosyanız varsa, aramanız gerekir:

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

Apk'a bakıp, her türlü karmaşık çözümü yükledikten / kaldırdıktan ve denedikten sonra, tam karşımdaki basit sorunu göremedim!


İşte buydu. Bilinmeyen bazı nedenlerden dolayı Android, pakette bulunsalar bile dosya adı 'lib' ile başlamayan kitaplıkları kurmaz.
George Y.

Bunu projede nerede kontrol edebilirim? Demek istediğim System.loadLibrary, kodda bu satırı nerede bulabilirim
aleksandrbel

Teşekkürler. Bu yardımcı oldu!
Riskhan

5

Bu bir Android 8 güncellemesidir.

Android'in önceki sürümlerinde, LoadLibrary yerel paylaşımlı kitaplıklara (örneğin JNI aracılığıyla erişim için), çeşitli apk kurulum / yükseltme algoritmalarına dayalı olarak lib klasörü için bir dizi potansiyel dizin yolu boyunca yineleme yapmak üzere yerel koduma donanımla bağlantı kurdum:

/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

Bu yaklaşım hokeydir ve Android 8 için çalışmayacaktır; dan https://developer.android.com/about/versions/oreo/android-8.0-changes.html onların "Güvenlik" bir parçası olarak artık sourceDir kullanmak gerekir değişiklikleri göreceksiniz:

"Artık APK'ların, adları -1 veya -2 ile biten dizinlerde bulunduğunu varsayamazsınız. Uygulamalar, dizini almak için sourceDir'i kullanmalı ve dizin biçimine doğrudan güvenmemelidir."

Düzeltme, sourceDir yerel paylaşılan kitaplıklarınızı bulmanın yolu değildir; gibi bir şey kullanın. Android 4.4.4 -> 8.0 için test edildi

// 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

Dahil etme PREBUILT_SHARED_LIBRARYbölümünden sonra kitaplığınızı aramaya çalışın :

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

Güncelleme:

Bu kitaplığı Java'da kullanacaksanız, onu paylaşılan kitaplık olarak derlemeniz gerekir.

LOCAL_PATH := $(call my-dir)

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

Ve kitaplığı /vendor/libdizinde dağıtmanız gerekir .


Sadece bölümün sonunda.
Alex

2

ABI'yı eski yapıları kullanmak için değiştirebilirsiniz:

defaultConfig {
    ...

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

Bu satırı şuraya ekleyerek kullanımdan kaldırılmış NDK'yi de kullanmalısınız gradle.properties:

android.useDeprecatedNdk=true

0

lütfen tüm desteği ekleyin

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
Ne yapacağınız konusunda biraz daha net konuşur musunuz?
EFrank

Projenizdeki .so dosyası. Arm64-v8a armeabi armeabi-v7a x86 x86_64 mips mips64'ü desteklemelisiniz. Bunu yaptığım zaman iyi çalışıyor.
Lion 耿

-1

Deneyimlerime göre, bir armeabi-v7a cep telefonunda, hem armeabi hem de armeabi-v7a dizinleri apk'de mevcut olduğunda, armeabi dizinindeki .so dosyaları bağlantılı olmayacak, ancak armeabi'deki .so dosyaları armeabi-v7a yoksa aynı armeabi-v7a mobile.


-1

Aslında, sadece bir .bu dosyayı koyamazsınız /libs/armeabi/ve ile yükleyebilirsiniz System.loadLibrary. Bir Android.mk dosyası oluşturmanız ve .so dosyanızı kaynak olarak belirttiğiniz önceden oluşturulmuş bir modül bildirmeniz gerekir.

Bunu yapmak için .so dosyanızı ve Android.mk dosyasını jniklasöre koyun . Android.mk'niz şöyle görünmelidir:

LOCAL_PATH := $(call my-dir)

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

Kaynak: Önceden oluşturulmuş hakkında Android NDK belgeleri

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.