Android NDK C ++ JNI (tidak ada implementasi yang ditemukan untuk native…)

88

Saya mencoba menggunakan NDK dengan C ++ dan sepertinya metode penamaan metode tidak benar. metode asli saya adalah sebagai berikut:

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

dengan tajuk yang dibungkus dengan "C" {} eksternal juga.

Semuanya dapat dikompilasi dengan baik, membuat file .so dan menyalin ke folder libs di bawah proyek saya, tetapi ketika saya men-debug dan menjalankan di Eclipse saya terus mendapatkan pesan log cat bahwa "tidak ada implementasi yang ditemukan untuk native ...". Apakah ada sesuatu yang saya lewatkan karena semua contoh NDK ada di C?

Terima kasih.

Patrick Kafka
sumber
Apakah Anda membuat stub JNI Anda menggunakan javah? Jika tidak, Anda harus. :-P
Chris Jester-Young
7
Kemungkinan besar karena Anda tidak meneleponSystem.loadLibrary
IgorGanapolsky
1
Terima kasih atas pertanyaan anda Saya belajar hal baru hari ini.
Shady Mohamed Sherif

Jawaban:

150

Ada beberapa hal yang dapat menyebabkan "penerapan tidak ditemukan". Salah satunya adalah mendapatkan nama prototipe fungsi yang salah, yang lainnya gagal memuat .so sama sekali. Apakah Anda yakin itu System.loadLibrary()dipanggil sebelum metode ini digunakan?

Jika Anda tidak memiliki JNI_OnLoadfungsi yang ditentukan, Anda mungkin ingin membuatnya dan mengeluarkan pesan log hanya untuk memverifikasi bahwa lib berhasil ditarik masuk.

Anda sudah menghindari masalah yang paling umum - lupa menggunakan extern "C"- jadi masalah di atas atau sedikit salah eja. Seperti apa deklarasi Java itu?

iseng
sumber
13
Astaga! Anda menghemat jam kerja saya - setelah membaca ini saya baru saja ingat saya mendapat komentar dari panggilan loadLibrary ...
zeboidlund
11
Anda menyelamatkan saya juga! Saya memeriksa nama fungsi saya empat kali lipat dan beberapa hal lainnya ... tetapi saya lupa "C" eksternal, dan bahkan tidak menyadarinya dalam pertanyaan!
Qwertie
1
Sekarang di situs dokumen Android: developer.android.com/training/articles/perf-jni.html#faq_ULE
fadden
2
ada juga satu kasus yang tidak diberitahukan siapa pun: Anda tidak dapat menggunakan '_' (garis bawah) dalam nama fungsi karena garis bawah diinterpretasikan sebagai pemisah paket. Jadi, hanya nama fungsi kasus unta yang dimungkinkan
Nulik
2
@Nulik: Anda dapat menggunakan '_' jika Anda meloloskannya sebagai "_1".
fadden
18

Penyebab tambahan untuk kesalahan ini: nama metode asli Anda yang tidak didekorasi tidak boleh mengandung garis bawah!

Misalnya, saya ingin mengekspor fungsi C bernama AudioCapture_Ping(). Ini deklarasi ekspor saya di C:

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

Inilah kelas Java saya yang mengimpor fungsinya:

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

Saya tidak bisa mendapatkan Android untuk secara dinamis menautkan ke metode asli saya sampai saya menghapus garis bawah:

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

sumber
6
Kemunculan '_' di deklarasi bahasa Java harus diganti dengan "_1" di deklarasi native. Lihat tabel 2-1 di docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/… .
fadden
1
Sangat jelas, namun saya tidak berhasil mengetahuinya sendiri setelah beberapa jam debugging ... Terima kasih, Anda menyelamatkan saya!
George Atsev
@ user1222021 Saya punya pertanyaan, dapatkah kita mengekspor metode cpp untuk semua aktivitas dalam proyek ini, apakah kita perlu menentukan nama aktivitas dalam metode dalam file .cpp?
Balflear
14

Saya memiliki masalah yang sama, tetapi bagi saya kesalahan itu ada di file Android.mk. Saya memilikinya:

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

tetapi harus memiliki ini:

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

perhatikan detail + = sebagai gantinya : =

Saya harap itu membantu.

ademar111190
sumber
2
Atau Anda dapat menambahkan semuanya dalam satu baris, atau menggunakan karakter pemisah baris `\`.
IgorGanapolsky
6

Disebut eksternal "C" seperti yang disediakan dalam contoh Studio yang dibuat secara otomatis, tetapi lupa untuk menggabungkan seluruh file lainnya, termasuk fungsi-fungsi berikut, dalam {} tanda kurung. Hanya fungsi pertama yang berhasil.

DragonLord
sumber
4

Alasan tambahan: Gunakan LOCAL_WHOLE_STATIC_LIBRARY sebagai ganti LOCAL_STATIC_LIBRARY di android.mk. Hal ini menghentikan library agar tidak mengoptimalkan panggilan API yang tidak digunakan karena NDK tidak dapat mendeteksi penggunaan binding native dari kode java.

John Twigg
sumber
1
Di mana perbedaan dalam: "Gunakan LOCAL_WHOLE_STATIC_LIBRARY sebagai ganti LOCAL_STATIC_LIBRARY di android.mk"
Josh
4

Ada contoh cpp di bawah aplikasi di ndk: https://github.com/android/ndk-samples/blob/master/hello-gl2/app/src/main/cpp/gl_code.cpp

Megha
sumber
2
Anda dapat menemukan file cpp di android-ndk / samples / hello-gl2 yang merupakan bagian dari distribusi Android NDK
Yenchi
1
@pevik Sudah mati lagi.
Mygod
tautan mati lagi
pengguna13107
2

Gunakan javah (bagian dari Java SDK). Ini adalah alat yang tepat untuk ini (menghasilkan header .h dari file .class).

MartinH
sumber
2

Jika nama paket Anda termasuk _ karakter, Anda harus menulis 1 (satu) setelah karakter _ seperti gambar di bawah ini:

MainActivity.java

package com.example.testcpp_2;

native-lib.cpp

JNICALL
Java_com_example_testcpp_12_MainActivity_stringFromJNI(
oiyio
sumber
0

Saya mencoba semua solusi di atas, tetapi tidak ada yang dapat menyelesaikan kesalahan build saya (jni java.lang.UnsatisfiedLinkError: Tidak ada implementasi yang ditemukan untuk ...), akhirnya saya menemukan bahwa saya lupa menambahkan file sumber verifikasi.cpp saya ke CMakeList.txt segmen add_library (verifikasi.cpp otomatis dibuat dengan Ctrl + Enter short key, mungkin nama file lain), semoga tanggapan saya dapat membantu seseorang.

lingkungan build saya: Gradle + CMake

pengguna2420449
sumber
0

Saya menghadapi masalah yang sama, dan dalam kasus saya, alasannya adalah karena saya telah menggarisbawahi dalam nama paket "RFID_Test" Saya mengganti nama Paket dan berhasil. Terima kasih user1222021

Firas Shrourou
sumber
-3

Saya menghadapi masalah yang sama dua kali. Kebetulan ponsel yang saya coba untuk memulai aplikasi dari Android Studio menggunakan level API yang belum saya unduh di Android Studio.

  1. Upgrade Android Studio ke versi terbaru
  2. Unduh API yang diperlukan dari dalam Android Studio
Yuliwee
sumber