System.loadLibrary (…) मेरे मामले में मूल पुस्तकालय नहीं खोज सका


91

मैं एक अन्य एंड्रॉइड प्रोजेक्ट से एक मौजूदा देशी लाइब्रेरी का उपयोग करना चाहता हूं , इसलिए मैंने अपने नए एंड्रॉइड प्रोजेक्ट में सिर्फ NDK निर्मित लाइब्रेरी ( libcalculate.so ) की प्रतिलिपि बनाई । अपने नए एंड्रॉइड प्रोजेक्ट में मैंने एक फ़ोल्डर बनाया libs/armeabi/और वहां libcalculate.so डाला । नहीं है कोई JNI / फ़ोल्डर। मेरे परीक्षण उपकरण में ARM आर्किटेक्चर है।

मेरे जावा कोड में मैं पुस्तकालय को लोड करता हूं:

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

जब मैं अपना नया एंड्रॉइड प्रोजेक्ट चलाता हूं, तो मुझे त्रुटि मिली:

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

इसलिए, जैसा कि त्रुटि कहती है, कॉपी की गई मूल लाइब्रेरी / वर्डॉर / लिब या / सिस्टम / लिब में नहीं है, मेरे मामले में इस समस्या को कैसे हल किया जाए?

(मैं एपीके पैकेज को अनज़िप कर दिया, लिब के तहत / लिबाकुलकेट है। एसो)

==== अद्यतन =====

मैंने प्रोजेक्ट रूट के तहत एक jni / folder बनाने की भी कोशिश की, और 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 के साथ) द्वारा उत्पन्न की जाती हैं।

फिर मैं अपने मावेन को सफलतापूर्वक परियोजना का निर्माण करता हूं। अंतिम एपीके पैकेज में, निम्न हैं:

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

लेकिन जब मैं अपना ऐप चलाता हूं, तो वही त्रुटि:

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

3
आप सीधे पुस्तकालय के तहत डाल दिया libs/? आपको संभवतः प्रति एबीबी एक उपनिर्देशिका बनाने की आवश्यकता है जिसे आप (armeabi, armeabi-v7a, x86, mips, आदि) का समर्थन करना चाहते हैं और प्रत्येक libs/armeabi/। आदि)।
माइकल

@ मिचेल, मुझे सिर्फ इतना याद है कि अपनी पोस्ट में, मैंने इसे वास्तव में libs / armeabi / के तहत रखा था
user842225

जाँच करें कि libcalculate.so वास्तव में पैकेजिंग प्रक्रिया द्वारा उठाया जाता है - उदाहरण के लिए unzip -l package.apk, या .zip के लिए एपीके का नाम बदलें और इसे कुछ एप्लिकेशन के साथ खोलें। यदि यह नहीं है, तो इसे पैकेजिंग के साथ कुछ गलत है (क्या आपके आईडीई ने फ़ोल्डर देखा है, क्या आपको परियोजना को ताज़ा करने की आवश्यकता है?)।
मस्तोरजो

@mstorsjo, मैंने एपीके पैकेज को अनवीप्ड किया, लिब के तहत / lib libculate.so है
user842225

1
आप एक Android.mk या किसी भी संकलन से संबंधित फ़ाइलों की जरूरत नहीं है। बस अपनी उपनिर्देशिकाओं के अनुसार यहाँ की तरह jniLibs में फाइल रखें: github.com/Ph1b/MaterialAudiobookPlayer/tree/master/audiobook/…
पॉल Woitaschex

जवाबों:


177

मूल कारण (और शायद उसी समय में आपकी समस्या हल हो जाए), यहाँ आप क्या कर सकते हैं:

  1. जेनी फ़ोल्डर और सभी .mk फ़ाइलों को निकालें । अगर आपको कुछ भी संकलन नहीं है, तो आपको इनकी और न ही NDK की जरूरत नहीं है।

  2. अपनी libcalculate.soफ़ाइल को अंदर कॉपी करें <project>/libs/(armeabi|armeabi-v7a|x86|...)। एंड्रॉइड स्टूडियो का उपयोग करते समय, यह है <project>/app/src/main/jniLibs/(armeabi|armeabi-v7a|x86|...), लेकिन मुझे लगता है कि आप ग्रहण का उपयोग कर रहे हैं।

  3. अपनी एपीके का निर्माण करें और इसे ज़िप फ़ाइल के रूप में खोलें, यह जांचने के लिए कि आपकी libcalculate.soफ़ाइल lib के अंदर है / (armeabi | armeabi-v7a | x86 | ...)

  4. अपना एप्लिकेशन निकालें और इंस्टॉल करें

  5. रन डंपस पैकेज | grep yourpackagename को अपने आवेदन की nativeLathPath या legacyNativeLibraryDir प्राप्त करने के लिए ।

  6. भागो ls पर nativeLibraryPath आप था या पर legacyNativeLibraryDir / armeabi अगर आपके libcalculate.so वास्तव में नहीं है, जांच करने के लिए।

  7. यदि यह वहां है, तो जांचें कि क्या यह आपके मूल libcalculate.so फ़ाइल से परिवर्तित नहीं किया गया है : क्या यह सही आर्किटेक्चर के खिलाफ संकलित है, क्या इसमें अपेक्षित प्रतीक शामिल हैं, क्या कोई लापता निर्भरताएं हैं। आप का उपयोग करके libcalculate.so का विश्लेषण कर सकते हैं।

चरण 5-7 की जांच करने के लिए, आप कमांड लाइन के बजाय मेरे एप्लिकेशन का उपयोग कर सकते हैं और पढ़ सकते हैं: नेटिव लिब्स मॉनिटर

पुनश्च: यह उलझन में पड़ना आसान है कि .so फाइलें कहां रखी जाएं या डिफ़ॉल्ट रूप से बनाई जाएं, यहां एक सारांश है:

  • एक ग्रहण परियोजना के अंदर libs / CPU_ABI

  • Android स्टूडियो प्रोजेक्ट के अंदर jniLibs / CPU_ABI

  • जानी / CPU_ABI एक AAR के अंदर

  • अंतिम APK के अंदर lib / CPU_ABI

  • ऐप के nativeLibraryPath के अंदर <5.0 डिवाइस पर, और ऐप के लेगेसी नेटिवलाइड्सDir / CPU_ARCH के अंदर > = 5.0 डिवाइस पर।

जहाँ CPU_ABI किसी भी प्रकार का है: armeabi, armeabi-v7a, arm64-v8a, x86, x86_64, mips, mips64 । इस बात पर निर्भर करता है कि आप किस आर्किटेक्चर को लक्षित कर रहे हैं और आपके लिबास का संकलन किया गया है।

यह भी ध्यान रखें कि CPU_ABI निर्देशिकाओं के बीच लिबास मिश्रित नहीं हैं: आपको जो भी उपयोग कर रहे हैं, उसके पूर्ण सेट की आवश्यकता है, armeabi फ़ोल्डर के अंदर एक लीब को armeabi-v7a डिवाइस पर स्थापित नहीं किया जाएगा यदि आर्मेबी के अंदर कोई भी लिबास हैं -v7a फ़ोल्डर एपीके से।


3
बहुत बढ़िया आदमी, धन्यवाद! मैं एंड्रॉइड स्टूडियो का उपयोग कर रहा हूं और jniLibs के बजाय मेरे jni बिल्ड को libs में कॉपी किया जा रहा है।
लुइस

4
पूर्ण सेट की जरूरत के बारे में आखिरी नोट मेरे लिए महत्वपूर्ण था। यह मेरी समस्या थी, धन्यवाद!
बेन ट्रेंग्रोव

के लिए 7अनुभाग: आप मतलब है .so APK से बदला जा सकता है कि यह डिवाइस पर स्थापित किया गया है के बाद? यदि ऐसा है तो एक मौका होगा। सिस्टम .so फ़ाइल को बर्बाद कर सकता है?
जयातुबी

5
आश्चर्यजनक! मेरे बहुत ही अजीब मामले में, मैं पुस्तकालयों (ओपनसीवी - आर्मएबी फ़ोल्डर में) के तीसरे पक्ष के सेट का उपयोग कर रहा था और जब मैंने ग्रैडल के माध्यम से एक अलग 3 पार्टी पुस्तकालय जोड़ा तो उन पुस्तकालयों ने लोड करना बंद कर दिया। यह पता चला है कि दूसरी लाइब्रेरी ARMv5 या 6 का समर्थन नहीं करती है, और इसे शामिल करने से, मेरी OpenCV लाइब्रेरी अदृश्य हो गई (हालांकि वे वास्तव में वहां थे )। पूर्ण सेट के बारे में आपकी बात ने मुझे सुराग दिया - आर्मएबी फ़ोल्डर का नाम बदलने और इसे आर्मेबी-वी 7 ए कहकर समस्या को ठीक किया (क्योंकि अब मैं एआरएम 5 या 6 का समर्थन नहीं करता ...)। बुराई की समस्या !!
मेट

1
एक और तरीका है कि अपनी लीबी फाइल (* .so) को कहां रखा जाए, अपने एप्लिकेशन को चलाएं और नेटवर्क्स को प्रिंट करें। आपको ABI प्रदान करता है।
डेविड राका

20

ग्रेड में, सभी फाइल फोल्डर को कॉपी करने के बाद libs/

jniLibs.srcDirs = ['libs']

फ़ाइल sourceSetsमें उपरोक्त पंक्ति जोड़कर build.gradleकाम किया। और कुछ भी काम नहीं किया।


2
"sourceSets" build.gradle फ़ाइल में स्थित थे?
आशना.जैकॉल

12

क्या आप ग्रेडेल का उपयोग कर रहे हैं? यदि ऐसा है तो .soफ़ाइल को अंदर रखें<project>/src/main/jniLibs/armeabi/

मुझे उम्मीद है यह मदद करेगा।


नहीं, मैं
ग्रेडेल

12

मेरे मामले में मुझे संकलित स्रोतों को बाहर करना चाहिए और लिबास पथ निर्धारित करना चाहिए

android {

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

यह मेरे लिए भी हल हो गया और मैंने armeabi-v7a और x86 फ़ोल्डरों में armeabi की फाइलें जोड़ीं, लेकिन मुझे यकीन नहीं है कि यह आवश्यक था।
dokam_scotland

8

इस त्रुटि का कारण यह है क्योंकि आपके ऐप और आपके द्वारा लिंक किए गए मूल पुस्तकालय के बीच ABI का एक बेमेल है। एक और शब्द, आपका ऐप और आपका .soलक्ष्य अलग-अलग ABI को लक्षित कर रहा है।

यदि आप नवीनतम एंड्रॉइड स्टूडियो टेम्प्लेट का उपयोग करके अपना ऐप बनाते हैं, तो संभवतः यह लक्ष्यीकरण है arm64-v8aलेकिन उदाहरण के लिए आपका .soलक्ष्य हो सकता है armeabi-v7a

इस समस्या को हल करने का 2 तरीका है:

  1. प्रत्येक ABI को आपके एप्लिकेशन समर्थन के लिए अपनी मूल लाइब्रेरी बनाएँ।
  2. आपके द्वारा .soबनाए गए पुराने ABI को लक्षित करने के लिए अपना ऐप बदलें ।

च्वाइस 2 गंदा है, लेकिन मुझे लगता है कि आपको शायद अधिक दिलचस्पी है:

अपना ऐप बदलें build.gradle

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

क्या होगा अगर मेरा ऐप मैं ग्रहण में? यह समस्या तब आ रही है जब मैं उसी अनुकूलित ऐप को 6 से 9 तक स्थानांतरित करता हूं
शैडो

6

संदर्भ के लिए, मेरे पास यह त्रुटि संदेश था और समाधान यह था कि जब आप लाइब्रेरी को निर्दिष्ट करते हैं तो आप सामने से 'लिबास' और अंत से '.so' को याद करते हैं।

इसलिए, यदि आपके पास एक फ़ाइल libmyfablib.so है, तो आपको कॉल करने की आवश्यकता है:

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

एपीके में देखे जाने के बाद, सभी प्रकार के जटिल समाधानों को स्थापित / अनइंस्टॉल किया गया और मैंने उन सरल समस्याओं को नहीं देखा, जो मेरे चेहरे के सामने सही थीं!


वह यह था। किसी अज्ञात कारण से Android उन पुस्तकालयों को स्थापित नहीं करता है जिनका फ़ाइल नाम 'lib' से शुरू नहीं होता है, भले ही वे पैकेज में मौजूद हों। गो फिगर ...
जॉर्ज वाई।

मैं इस परियोजना में कहां जांच कर सकता हूं? मेरा मतलब है कि मुझे System.loadLibraryकोड में यह रेखा कहां मिल सकती है
aleksandrbel

धन्यवाद। इससे मदद मिली!
रिचन

5

यह एक एंड्रॉइड 8 अपडेट है।

एंड्रॉइड के पहले संस्करण में, लोड किए गए देशी साझा लाइब्रेरीज़ (उदाहरण के लिए जेएनआई के माध्यम से एक्सेस के लिए) मैंने विभिन्न एपीके इंस्टॉलेशन / अपग्रेड लोकम्स के आधार पर अपने मूल कोड को लिबर्ट फ़ोल्डर के लिए संभावित निर्देशिका पथों की श्रेणी के माध्यम से पुनरावृत्त करने के लिए हार्ड-वायर्ड किया है:

/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

यह दृष्टिकोण हॉकी है और एंड्रॉइड 8 के लिए काम नहीं करेगा; से https://developer.android.com/about/versions/oreo/android-8.0-changes.html आप देखेंगे कि उनके "सुरक्षा" के भाग के रूप में आप अब sourceDir उपयोग करने की आवश्यकता परिवर्तन:

"आप अब यह नहीं मान सकते हैं कि एपीके उन निर्देशिकाओं में रहता है जिनके नाम -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

अपडेट करें:

यदि आप जावा में इस पुस्तकालय का उपयोग करेंगे तो आपको इसे साझा पुस्तकालय के रूप में संकलित करने की आवश्यकता है

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'
    }
    ...
}

आपको इस पंक्ति को जोड़कर घटित NDK का उपयोग करना चाहिए gradle.properties:

android.useDeprecatedNdk=true

0

कृपया सभी सुपरपोर्ट जोड़ें

एप्लिकेशन / build.gradle

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

एप्लिकेशन \ 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 mips64 समर्थन करना चाहिए। जब मैं ऐसा कर रहा था, तो यह अच्छी तरह से काम करता है।
सिंह 耿

-1

मेरे अनुभव में, एक armeabi-v7a मोबाइल में, जब armeabi और armeabi-v7a दोनों डायरेक्टरी एपीके में मौजूद हैं, तो armeabi डायरेक्टरी में .so फाइलें लिंक नहीं की जाएंगी, हालांकि आर्मएबी में .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)

स्रोत: Prebuilt के बारे में Android NDK प्रलेखन

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.