Android NDK C ++ JNI (nenhuma implementação encontrada para nativo…)

86

Estou tentando usar o NDK com C ++ e não consigo obter a convenção de nomenclatura de método correta. meu método nativo é o seguinte:

extern "C" {
JNIEXPORT void JNICALL Java_com_test_jnitest_SurfaceRenderer_drawFromJni
(JNIEnv* env, jclass c)
{
   //
}
}

com um cabeçalho envolvido em extern "C" {} também.

Tudo compila bem, cria um arquivo .so e copia para a pasta libs em meu projeto, mas quando eu depuro e executo no Eclipse, continuo recebendo uma mensagem de log cat de "nenhuma implementação encontrada para nativo ...". Há algo que estou perdendo, pois todos os exemplos de NDK estão em C?

Obrigado.

Patrick Kafka
fonte
Você está gerando seus stubs JNI usando javah? Se não, você deveria estar. :-P
Chris Jester-Young
7
Provavelmente porque você não ligouSystem.loadLibrary
IgorGanapolsky
1
Obrigado por sua pergunta. Aprendi uma coisa nova hoje.
Shady Mohamed Sherif

Respostas:

146

Existem algumas coisas que podem levar a "nenhuma implementação encontrada". Um está obtendo o nome do protótipo da função errado, outro está deixando de carregar o .so. Tem certeza de que System.loadLibrary()está sendo chamado antes de o método ser usado?

Se você não tem uma JNI_OnLoadfunção definida, você pode querer criar uma e fazer com que ela exiba uma mensagem de log apenas para verificar se a lib está sendo puxada com sucesso.

Você já se esquivou do problema mais comum - esquecer de usar extern "C"- então é o acima ou algum pequeno erro de ortografia. Qual é a aparência da declaração Java?

fadden
fonte
13
Jesus! Você me poupou horas de trabalho - ao ler isso, acabei de lembrar que tive minha chamada loadLibrary comentada ...
zeboidlund
11
Você me salvou também! Verifiquei quádruplamente o nome da minha função e algumas outras coisas ... mas esqueci o extern "C" e nem percebi na pergunta!
Qwertie
1
Agora no site de documentos do Android: developer.android.com/training/articles/perf-jni.html#faq_ULE
fadden
2
há também um caso sobre o qual ninguém falou: você não pode usar '_' (sublinhados) em nomes de funções, pois os sublinhados são interpretados como separadores de pacote. Portanto, apenas nomes de função de caixa de camelo são possíveis
Nulik
2
@Nulik: você pode usar '_' se você escapar como "_1".
fadden
18

Uma causa adicional para esse erro: o nome do método nativo não decorado não deve conter sublinhado!

Por exemplo, eu queria exportar uma função C chamada AudioCapture_Ping(). Aqui está minha declaração de exportação em C:

JNI_EXPORT int Java_com_obsidian_mobilehashhost_MainActivity_AudioCapture_Ping(JNIEnv *pJniEnv, jobject object);  //Notice the underscore before Ping

Aqui estava minha classe Java importando a função:

package com.obsidian.mobileaudiohashhost;
...
public class MainActivity extends Activity {
    private native int AudioCapture_Ping();  // FAILS
    ...

Não consegui que o Android se vinculasse dinamicamente ao meu método nativo até remover o sublinhado:

JNI_EXPORT int Java_com_obsidian_mobilehashhost_MainActivity_AudioCapturePing(JNIEnv *pJniEnv, jobject object); 

package com.obsidian.mobileaudiohashhost;
...
public class MainActivity extends Activity {
    private native int AudioCapturePing();  // THIS WORKS!
    ...

fonte
5
As ocorrências de '_' na declaração da linguagem Java devem ser substituídas por "_1" na declaração nativa. Consulte a tabela 2-1 em docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/… .
fadden
1
Tão óbvio, mas não consegui descobrir sozinho depois de várias horas de depuração ... Obrigado, você me salvou!
George Atsev
@ user1222021 Tenho uma pergunta, podemos exportar o método cpp para todas as atividades do projeto, precisamos especificar o nome da atividade no método no arquivo .cpp?
Balflear
14

Tive o mesmo problema, mas para mim o erro estava no arquivo Android.mk. Eu tinha isso:

LOCAL_SRC_FILES := A.cpp
LOCAL_SRC_FILES := B.cpp 

mas deveria ter isto:

LOCAL_SRC_FILES := A.cpp
LOCAL_SRC_FILES += B.cpp 

observe o detalhe + = ao invés : =

Espero que ajude.

ademar111190
fonte
2
Ou você pode simplesmente adicioná-los todos em uma linha, ou usar o caractere de quebra de linha `\`.
IgorGanapolsky
6

Chamado extern "C" conforme fornecido no exemplo do Studio gerado automaticamente, mas esqueci de envolver todo o restante do arquivo, incluindo as funções a seguir, entre {} colchetes. Apenas a primeira função funcionou.

DragonLord
fonte
4

Um motivo adicional: use LOCAL_WHOLE_STATIC_LIBRARIES em vez de LOCAL_STATIC_LIBRARIES no android.mk. Isso impede que a biblioteca otimize as chamadas API não utilizadas porque o NDK não pode detectar o uso de ligações nativas do código java.

John Twigg
fonte
1
Onde está a diferença em: "Use LOCAL_WHOLE_STATIC_LIBRARIES em vez de LOCAL_STATIC_LIBRARIES em android.mk"
Josh
4

Há um exemplo de cpp em apps em ndk: https://github.com/android/ndk-samples/blob/master/hello-gl2/app/src/main/cpp/gl_code.cpp

Megha
fonte
2
você pode encontrar o arquivo cpp em android-ndk / samples / hello-gl2 que faz parte da distribuição Android NDK
Yenchi
1
@pevik Está morto novamente.
Mygod
link está morto novamente
user13107
2

Use javah (parte do Java SDK). É a ferramenta exatamente para isso (gera o cabeçalho .h do arquivo .class).

MartinH
fonte
2

Se o nome do seu pacote inclui _ caractere, você deve escrever 1 (um) após _ caractere, conforme mostrado abaixo:

MainActivity.java

package com.example.testcpp_2;

native-lib.cpp

JNICALL
Java_com_example_testcpp_12_MainActivity_stringFromJNI(
Oiyio
fonte
0

Tento todas as soluções acima, mas ninguém consegue resolver meu erro de compilação (jni java.lang.UnsatisfiedLinkError: Nenhuma implementação encontrada para ...), finalmente descobri que esqueci de adicionar meu arquivo de origem verify.cpp em CMakeList.txt segmento add_library (verify.cpp é gerado automaticamente pela tecla curta Ctrl + Enter, talvez outro nome de arquivo), espero que minha resposta possa ajudar alguém.

meu ambiente de construção: Gradle + CMake

user2420449
fonte
0

Eu enfrentei o mesmo problema e, no meu caso, o motivo foi que eu tinha sublinhado no nome do pacote "RFID_Test". Renomeei o pacote e funcionou. Obrigado user1222021

Firas Shrourou
fonte
-3

Eu enfrentei o mesmo problema duas vezes. Acontece que o telefone que tentei iniciar o aplicativo do Android Studio usava um nível de API que ainda não baixei no Android Studio.

  1. Atualize o Android Studio para a versão mais recente
  2. Baixe a API necessária de dentro do Android Studio
Yuliwee
fonte