System.loadLibrary (…) não conseguiu encontrar a biblioteca nativa no meu caso

91

Quero usar uma biblioteca nativa existente de outro projeto Android, então apenas copiei a biblioteca construída do NDK ( libcalculate.so ) para meu novo projeto Android. No meu novo projeto Android, criei uma pasta libs/armeabi/e coloquei libcalculate.so lá. Não jni / pasta. Meu dispositivo de teste tem arquitetura ARM.

No meu código java, carrego a biblioteca:

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

Quando executo meu novo projeto android, recebo o erro:

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

Então, como diz o erro, a biblioteca nativa copiada não está em / verdor / lib ou / system / lib, como resolver esse problema no meu caso?

(Descompactei o pacote apk, em lib / há libcalculate.so)

==== ATUALIZAÇÃO =====

Também tentei criar uma pasta jni / na raiz do projeto e adicionar um arquivo Android.mk em jni /. O conteúdo do Android.mk é:

LOCAL_PATH := $(call my-dir)

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

Então, na raiz do projeto, executei o ndk-build. Depois disso, os diretórios armeabi / e armeabi-v7a / são gerados pelo ndk-build (com libcalculate.so dentro da pasta).

Então eu executo meu maven para construir o projeto com sucesso. No pacote apk final, existem:

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

Mas quando executo meu aplicativo, o mesmo erro ocorre:

java.lang.UnsatisfiedLinkError:  ...
nativeLibraryDirectories=[/vendor/lib, /system/lib]]] couldn't find "libcalculate.so"
user842225
fonte
3
Você colocou a biblioteca diretamente abaixo libs/? Você provavelmente precisa criar um subdiretório por ABI de destino que deseja oferecer suporte (armeabi, armeabi-v7a, x86, mips, etc) e colocar o arquivo .so apropriado em cada subdiretório (ou seja, o arquivo .so construído para armeabi entra libs/armeabi/, etc).
Michael
@Michael, eu perdi isso na minha postagem, na verdade coloquei em libs / armeabi /
user842225
Verifique se libcalculate.so é realmente captado pelo processo de empacotamento - tente unzip -l package.apk, por exemplo , ou renomeie o apk para .zip e abra-o com algum aplicativo. Se não estiver lá, algo está errado com o empacotamento (seu IDE percebeu que a pasta está lá, você precisa atualizar o projeto?).
mstorsjo
@mstorsjo, descompactei o pacote apk, em lib / há libcalculate.so
user842225
1
você não precisa ter um Android.mk ou qualquer arquivo relacionado à compilação. Basta colocar os arquivos so em seus respectivos subdiretórios para jniLibs como aqui: github.com/Ph1b/MaterialAudiobookPlayer/tree/master/audiobook/…
Paul Woitaschek

Respostas:

174

Para solucionar a causa (e talvez resolver seu problema ao mesmo tempo), aqui está o que você pode fazer:

  1. Remova a pasta jni e todos os arquivos .mk . Você não precisa deles nem do NDK se não estiver compilando nada.

  2. Copie seu libcalculate.soarquivo dentro <project>/libs/(armeabi|armeabi-v7a|x86|...). Ao usar o Android Studio, é <project>/app/src/main/jniLibs/(armeabi|armeabi-v7a|x86|...), mas vejo que você está usando o eclipse.

  3. Construa seu APK e abra-o como um arquivo zip , para verificar se seu libcalculate.soarquivo está dentro de lib / (armeabi | armeabi-v7a | x86 | ...) .

  4. Remova e instale seu aplicativo

  5. Execute pacotes de pacote dumpsys | grep yourpackagename para obter o nativeLibraryPath ou legacyNativeLibraryDir de seu aplicativo.

  6. Execute ls em nativeLibraryPath que você tinha ou em legacyNativeLibraryDir / armeabi , para verificar se seu libcalculate.so está realmente lá.

  7. Se estiver lá, verifique se não foi alterado em relação ao arquivo libcalculate.so original : ele foi compilado com a arquitetura correta, contém os símbolos esperados, há alguma dependência ausente. Você pode analisar libcalculate.so usando readelf.

Para verificar a etapa 5 a 7, você pode usar meu aplicativo em vez das linhas de comando e ler: Native Libs Monitor

PS: É fácil se confundir sobre onde os arquivos .so devem ser colocados ou gerados por padrão. Aqui está um resumo:

  • libs / CPU_ABI dentro de um projeto eclipse

  • jniLibs / CPU_ABI dentro de um projeto Android Studio

  • jni / CPU_ABI dentro de um AAR

  • lib / CPU_ABI dentro do APK final

  • dentro do nativeLibraryPath do aplicativo em um dispositivo <5.0 e dentro do legacyNativeLibraryDir / CPU_ARCH do aplicativo em um dispositivo> = 5.0.

Onde CPU_ABI é qualquer um dos seguintes: armeabi, armeabi-v7a, arm64-v8a, x86, x86_64, mips, mips64 . Dependendo de quais arquiteturas você está almejando e para as quais suas bibliotecas foram compiladas.

Observe também que as libs não são misturadas entre os diretórios CPU_ABI: você precisa do conjunto completo do que está usando, uma lib que está dentro da pasta armeabi não será instalada em um dispositivo armeabi-v7a se houver libs dentro da armeabi -v7a pasta do APK.

ph0b
fonte
3
Homem incrível, obrigado! Estou usando o Android Studio e minhas compilações jni estavam sendo copiadas para libs em vez de jniLibs.
Luis
4
Essa última nota sobre a necessidade do conjunto completo foi crucial para mim. Esse foi o meu problema, obrigado!
Ben Trengrove
Para a 7seção: você quer dizer que o .so pode ser alterado do APK após ter sido instalado no dispositivo? Em caso afirmativo, haveria uma chance de o sistema danificar o arquivo .so?
jayatubi,
5
Maravilhoso! No meu caso muito estranho, eu estava usando um conjunto de bibliotecas de terceiros (OpenCV - na pasta armeabi ) e essas bibliotecas pararam de carregar quando adicionei uma biblioteca de terceiros diferente via Gradle. Acontece que a segunda biblioteca não oferece suporte a ARMv5 ou 6 e, ao incluí-la, minhas bibliotecas OpenCV se tornaram invisíveis (embora estivessem realmente lá ). Seu comentário sobre o conjunto completo me deu uma pista - renomear a pasta armeabi e chamá-la de armeabi-v7a resolveu o problema (já que agora não tenho suporte para ARM 5 ou 6 ...). Problema do mal !!
Mete
1
Outra maneira de descobrir onde colocar seu arquivo lib (* .so) é executar seu aplicativo e imprimir o nativeLibraryDir usando: System.out.println (getApplicationContext (). GetApplicationInfo (). NativeLibraryDir), o nome do diretório também será fornecer a você a ABI.
David Rauca de
19

No gradle, depois de copiar todas as pastas de arquivos para libs/

jniLibs.srcDirs = ['libs']

Adicionando a linha acima para sourceSetsno build.gradlearquivo funcionou. Nada mais funcionou de forma alguma.

Mukund Muralikrishnan
fonte
2
onde está "sourceSets" localizado no arquivo build.gradle?
Ashana.Jackol
12

Você está usando o Gradle? Se assim for, coloque o .soarquivo em<project>/src/main/jniLibs/armeabi/

Espero que ajude.

Assaf Gamliel
fonte
não, não estou usando o gradle, estou usando o eclipse + maven
user842225
12

No meu caso, devo excluir as fontes de compilação pelo gradle e definir o caminho das libs

android {

    ...
    sourceSets {
        ...
        main.jni.srcDirs = []
        main.jniLibs.srcDirs = ['libs']
    }
....
Dawid Drozd
fonte
isso resolveu para mim também e adicionei os arquivos do armeabi nas pastas armeabi-v7a e x86, mas não tenho certeza se foi necessário.
dokam_scotland
8

O motivo desse erro é porque há uma incompatibilidade de ABI entre seu aplicativo e a biblioteca nativa à qual você vinculou. Em outras palavras, seu aplicativo e seu .sotêm como alvo ABI diferentes.

se você criar seu aplicativo usando os modelos mais recentes do Android Studio, ele provavelmente terá como alvo o, arm64-v8amas seu .sopode ser o alvo, armeabi-v7apor exemplo.

Existem duas maneiras de resolver este problema:

  1. construir suas bibliotecas nativas para cada ABI que seu aplicativo suporte.
  2. mude seu aplicativo para ter como alvo ABI mais antigo que você .soconstruiu.

A escolha 2 é suja, mas acho que você provavelmente tem mais interesse em:

mude o do seu aplicativo build.gradle

android {
    defaultConfig {
        ...
        ndk {
            abiFilters 'armeabi-v7a'
        }
   }
}
Wdanxna
fonte
e se meu aplicativo estiver em eclipse? Esse problema surge quando eu migro o mesmo aplicativo personalizado de 6 para 9.
Shadow
6

Para referência, recebi esta mensagem de erro e a solução foi que quando você especifica a biblioteca, você perde o 'lib' na frente e o '.so' no final.

Portanto, se você tiver um arquivo libmyfablib.so, precisará chamar:

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

Tendo olhado no apk, instalado / desinstalado e tentado todos os tipos de soluções complexas, eu não conseguia ver o problema simples que estava bem na minha frente!

Andy Krouwel
fonte
Foi isso. Por alguma razão desconhecida, o Android não instala bibliotecas cujo nome de arquivo não começa com 'lib', mesmo que estejam presentes no pacote. Vai entender ...
George Y.
Onde posso verificar isso no projeto? Quer dizer, onde posso encontrar esta linha System.loadLibraryno código
aleksandrbel de
Obrigado. Isso ajudou!
Riskhan
5

Esta é uma atualização do Android 8.

Na versão anterior do Android, para carregar bibliotecas compartilhadas nativas (para acesso via JNI, por exemplo), conectei meu código nativo para iterar por meio de uma gama de caminhos de diretório potenciais para a pasta lib, com base nos vários algoritmos de instalação / atualização de 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

Essa abordagem é piegas e não funciona no Android 8; em https://developer.android.com/about/versions/oreo/android-8.0-changes.html, você verá que, como parte de suas alterações de "Segurança", agora você precisa usar sourceDir:

"Você não pode mais supor que os APKs residam em diretórios cujos nomes terminam em -1 ou -2. Os aplicativos devem usar sourceDir para obter o diretório e não depender diretamente do formato do diretório."

Correção, sourceDir não é a maneira de encontrar suas bibliotecas compartilhadas nativas; use algo parecido. Testado para 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
fonte
4

Tente ligar para sua biblioteca após incluir a PREBUILT_SHARED_LIBRARYseção:

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

Atualizar:

Se você usar esta biblioteca em Java, você precisa compilá-la como uma biblioteca compartilhada

LOCAL_PATH := $(call my-dir)

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

E você precisa implantar a biblioteca no /vendor/libdiretório.

Alex
fonte
Apenas no final da seção.
Alex
2

Você pode apenas alterar a ABI para usar compilações mais antigas:

defaultConfig {
    ...

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

Você também deve usar o NDK obsoleto adicionando esta linha a gradle.properties:

android.useDeprecatedNdk=true
rezam
fonte
0

por favor adicione todo o suporte

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
Leão 耿
fonte
1
Você poderia ser mais específico sobre o que fazer?
EFrank
O arquivo .so em seu projeto. Você deve ter suporte arm64-v8a armeabi armeabi-v7a x86 x86_64 mips mips64. Quando eu estava fazendo isso, funcionou bem.
Leão 耿
-1

Na minha experiência, em um armeabi-v7a mobile, quando os diretórios armeabi e armeabi-v7a estão presentes no apk, os arquivos .so no diretório armeabi não serão vinculados, embora os arquivos .so em armeabi SEJAM vinculados no mesmo armeabi-v7a móvel, se armeabi-v7a não estiver presente.

loopscn
fonte
-1

na verdade, você não pode simplesmente colocar um arquivo .so no /libs/armeabi/e carregá-lo com System.loadLibrary. Você precisa criar um arquivo Android.mk e declarar um módulo pré-construído onde você especifica seu arquivo .so como uma fonte.

Para fazer isso, coloque seu arquivo .so e o arquivo Android.mk na jnipasta. Seu Android.mk deve ser parecido com isto:

LOCAL_PATH := $(call my-dir)

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

Fonte: documentação do Android NDK sobre pré-construído

Yannshu
fonte