System.loadLibrary(…)が私の場合、ネイティブライブラリを見つけることができませんでした


91

別の 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 /フォルダーを作成し、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を実行しました。その後、ndk-buildによってarmeabi /およびarmeabi-v7a /ディレクトリが生成されます(フォルダー内に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など)ごとに1つのサブディレクトリを作成し、適切な.soファイルを各サブディレクトリに配置する必要があります(つまり、armeabi用に構築された.soファイルはlibs/armeabi/、等)。
マイケル

@Michael、私は自分の投稿でそれを見逃しました、実際にはlibs / armeabi /の下に置きました
user842225

libcalculate.soがパッケージングプロセスによって実際に取得されることを確認しunzip -l package.apkます。たとえば、を試すか、apkの名前を.zipに変更して、アプリケーションで開きます。存在しない場合は、パッケージ化に問題があります(IDEはフォルダーが存在することを認識しましたか?プロジェクトを更新する必要がありますか?)。
mstorsjo 2014

@mstorsjo、私はapkパッケージをlib /の下に解凍しました/ libcalculate.so
user842225

1
Android.mkやコンパイル関連のファイルは必要ありません。:ちょうどここのようなjniLibsに自分応じて、サブディレクトリ内のファイルので入れgithub.com/Ph1b/MaterialAudiobookPlayer/tree/master/audiobook/...
ポールWoitaschek

回答:


174

根本的な原因(そしておそらく同時に問題を解決すること)のために、あなたができることはここにあります:

  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をビルドしてzipファイルとして開き、libcalculate.soファイルがlib /(armeabi | armeabi-v7a | x86 | ...)内にあることを確認します。

  4. アプリケーションを削除してインストールする

  5. dumpsysパッケージパッケージを実行します。yourpackagenameをgrepし得るためにnativeLibraryPathまたはlegacyNativeLibraryDirアプリケーションのを。

  6. 持っているnativeLibraryPathまたはlegacyNativeLibraryDir / armeabilsを実行して、libcalculate.soが実際にそこにあるかどうかを確認します。

  7. そこにある場合は、元のlibcalculate.soファイルから変更されていないかどうかを確認します。適切なアーキテクチャーに対してコンパイルされているか、予想されるシンボルが含まれているか、依存関係が不足していないか。readelfを使用してlibcalculate.soを分析できます。

ステップ5-7を確認するために、コマンドラインやreadelfの代わりに私のアプリケーションを使用できます:Native Libs Monitor

PS:.soファイルをデフォルトで配置または生成する場所について混乱するのは簡単です。概要は次のとおりです。

  • Eclipseプロジェクト内のlibs / CPU_ABI

  • Android Studioプロジェクト内のjniLibs / CPU_ABI

  • AAR内のjni / CPU_ABI

  • 最終APK内のlib / CPU_ABI

  • アプリの内部nativeLibraryPathオン<5.0デバイス、およびアプリケーションの内部legacyNativeLibraryDir / CPU_ARCHに> = 5.0デバイス。

ここで、CPU_ABIは次のいずれかです:armeabi、armeabi-v7a、arm64-v8a、x86、x86_64、mips、mips64。ターゲットとするアーキテクチャーとライブラリーがコンパイルされているかどうかによって異なります。

あなたが使用しているもののフルセット、内側にあるlibに必要です:LIBSはCPU_ABIのディレクトリ間で混合されないことにも注意してください armeabiにインストールされませんフォルダarmeabi-v7aの内部の任意のlibsにある場合、デバイスarmeabiを APKから-v7aフォルダー。


3
素晴らしい男、ありがとう!Android Studioを使用していますが、jniビルドがjniLibsではなくlibsにコピーされていました。
Luis

4
フルセットが必要であるという最後のメモは、私にとって非常に重要でした。それは私の問題でした、ありがとう!
ベントレングローブ、2015年

以下のための7セクション:あなたはそれをデバイスにインストールされた後の.soはAPKから変更される場合があります意味ですか?もしそうなら、システムが.soファイルを台無しにする可能性がありますか?
jayatubi

5
素晴らしい!私の非常に奇妙なケースでは、サードパーティのライブラリセット(OpenCV- armeabiフォルダー内)を使用していて、Gradleを介して別のサードパーティライブラリを追加すると、それらのライブラリの読み込みが停止しました。2番目のライブラリはARMv5または6をサポートしていないことがわかりました。これを含めることで、私のOpenCVライブラリは見えなくなりました(実際にはそこにありました)。フルセットについてのあなたのポイントは私に手掛かりを与えました-armeabiフォルダーの名前を変更し、それをarmeabi-v7aと呼ぶことは問題を修正しました(私は現在ARM 5または6をサポートしていないため...)。邪悪な問題!!
メテ2015年

1
libファイル(* .so)を置く場所を見つけるもう1つの方法は、アプリケーションを実行し、次のコマンドを使用してnativeLibraryDirを印刷することです。System.out.println(getApplicationContext()。getApplicationInfo()。nativeLibraryDir)、ディレクトリの名前もABIを提供します。
David Rauca、2017年

19

Gradleでは、すべてのファイルフォルダをにコピーした後 libs/

jniLibs.srcDirs = ['libs']

上記の行を追加sourceSetsしてbuild.gradleファイルを働いていました。他には何も機能しませんでした。


2
「sourceSets」はbuild.gradleファイルにありましたか?
Ashana.Jackol

12

Gradleを使用していますか?もしそうなら、.soファイルを入れてください<project>/src/main/jniLibs/armeabi/

お役に立てば幸いです。


いいえ、私は+ MavenのEclipseを使用しています、のGradleを使用していない
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います.soarmeabi-v7a、たとえばをターゲットにしている可能性があります。

この問題を解決するには2つの方法があります。

  1. アプリがサポートするABIごとにネイティブライブラリを構築します。
  2. アプリを変更して、作成した古いABIをターゲットにします.so

選択肢2は汚いですが、おそらく次のことにもっと興味があると思います。

アプリを変更する build.gradle

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

私のアプリが日食の場合はどうなりますか?この問題は、私が6から9に同じカスタマイズされたアプリケーションを移行する際に来ている
シャドウ

6

参考までに、このエラーメッセージが表示されましたが、解決策は、ライブラリを指定するときに、「lib」を前から外し、「。so」を最後から外すことです。

したがって、ファイルlibmyfablib.soがある場合は、次を呼び出す必要があります。

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

apkを見て、インストール/アンインストールして、あらゆる種類の複雑なソリューションを試してみたところ、目の前にある簡単な問題を見つけることができませんでした。


それだけでした。不明な理由により、パッケージにファイル名が含まれていても、ファイル名が「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ディレクトリーにデプロイする必要があります。


セクションの最後のみ。
Alex

2

古いビルドを使用するようにABIを変更することもできます。

defaultConfig {
    ...

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

また、次の行を追加して、非推奨のNDKを使用する必要がありますgradle.properties

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をサポートしている必要があります。私がそれをしたとき、それはうまくいきます。
ライオンSSep

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