Android NDK C ++ JNI (ไม่พบการใช้งานสำหรับเนทีฟ ... )


88

ฉันกำลังพยายามใช้ NDK กับ C ++ และดูเหมือนจะไม่สามารถกำหนดวิธีการตั้งชื่อที่ถูกต้องได้ วิธีดั้งเดิมของฉันมีดังนี้:

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

ที่มีส่วนหัวห่อด้วย "C" {} ภายนอกเช่นกัน

ทุกอย่างคอมไพล์ได้ดีสร้างไฟล์. so และคัดลอกไปยังโฟลเดอร์ libs ภายใต้โปรเจ็กต์ของฉัน แต่เมื่อฉันดีบักและเรียกใช้ใน Eclipse ฉันยังคงได้รับข้อความบันทึกแมวว่า "ไม่พบการใช้งานสำหรับเนทีฟ ... " มีบางอย่างที่ฉันขาดหายไปเนื่องจากตัวอย่าง NDK ทั้งหมดอยู่ใน C หรือไม่

ขอบคุณ.


คุณกำลังสร้าง JNI Stubs โดยใช้javahหรือไม่? ถ้าไม่คุณควรจะเป็น :-P
Chris Jester-Young

7
ส่วนใหญ่เป็นเพราะคุณไม่ได้โทรSystem.loadLibrary
IgorGanapolsky

1
ขอบคุณสำหรับคำถามของคุณ ฉันได้เรียนรู้สิ่งใหม่ในวันนี้
Shady Mohamed Sherif

คำตอบ:


150

มีสองสิ่งที่อาจทำให้ "ไม่พบการนำไปใช้งาน" หนึ่งได้รับชื่อต้นแบบของฟังก์ชันผิดอีกอันหนึ่งไม่สามารถโหลด. ดังนั้นเลย แน่ใจหรือว่าSystem.loadLibrary()ถูกเรียกก่อนที่จะใช้วิธีนี้?

หากคุณไม่ได้JNI_OnLoadกำหนดฟังก์ชันไว้คุณอาจต้องการสร้างขึ้นมาและให้มันพ่นข้อความบันทึกเพื่อยืนยันว่า lib ถูกดึงเข้ามาสำเร็จ

คุณได้หลีกเลี่ยงปัญหาที่พบบ่อยที่สุดแล้ว - ลืมใช้งานextern "C"- ดังนั้นอาจเป็นสาเหตุข้างต้นหรือการสะกดผิดเล็กน้อย การประกาศ Java มีลักษณะอย่างไร?


13
พระเยซู! คุณช่วยฉันได้หลายชั่วโมงในการทำงาน - เมื่ออ่านสิ่งนี้ฉันเพิ่งจำได้ว่าฉันมีการโทรโหลดห้องสมุดแสดงความคิดเห็น ...
zeboidlund

11
คุณช่วยฉันด้วย! ฉันตรวจสอบชื่อฟังก์ชั่นของฉันเป็นสี่เท่าและอีกสองอย่าง ... แต่ฉันลืม "C" ภายนอกและไม่ได้สังเกตด้วยซ้ำในคำถาม!
Qwertie

1
ตอนนี้บนไซต์เอกสาร Android: developer.android.com/training/articles/perf-jni.html#faq_ULE
fadden

2
นอกจากนี้ยังมีอีกกรณีหนึ่งที่ไม่มีใครบอกเกี่ยวกับ: คุณไม่สามารถใช้ '_' (ขีดล่าง) ในชื่อฟังก์ชันได้เนื่องจากขีดล่างถูกตีความเป็นตัวคั่นแพ็กเกจ ดังนั้นจึงเป็นไปได้เฉพาะชื่อฟังก์ชันกรณีอูฐเท่านั้น
Nulik

2
@ นูลิก: คุณสามารถใช้ '_' ถ้าคุณหนีเป็น "_1"
fadden

18

สาเหตุเพิ่มเติมสำหรับข้อผิดพลาดนี้: ชื่อเมธอดเนทีฟที่ไม่ได้ตกแต่งของคุณต้องไม่มีขีดล่าง!

ตัวอย่างเช่นผมต้องการที่จะส่งออกฟังก์ชัน C AudioCapture_Ping()ชื่อ นี่คือใบแจ้งการส่งออกของฉันใน C:

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

นี่คือคลาส Java ของฉันที่นำเข้าฟังก์ชัน:

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

ฉันไม่สามารถให้ Android เชื่อมโยงกับเมธอดดั้งเดิมของฉันแบบไดนามิกได้จนกว่าฉันจะลบขีดล่าง:

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

6
การเกิด "_" ในการประกาศภาษา Java จะต้องแทนที่ด้วย "_1" ในการประกาศดั้งเดิม ดูตาราง 2-1 ในdocs.oracle.com/javase/7/docs/technotes/guides/jni/spec/...
fadden

1
เห็นได้ชัด แต่ฉันไม่สามารถจัดการได้ด้วยตัวเองหลังจากผ่านไปหลายชั่วโมงของการดีบั๊ก ... ขอบคุณคุณช่วยฉัน!
George Atsev

@ user1222021 ฉันมีคำถามเราสามารถส่งออกเมธอด cpp สำหรับกิจกรรมทั้งหมดในโปรเจ็กต์ได้ไหมเราจำเป็นต้องระบุชื่อกิจกรรมในเมธอดในไฟล์. cpp หรือไม่
Balflear

14

ฉันมีปัญหาเดียวกัน แต่สำหรับฉันแล้วข้อผิดพลาดอยู่ในไฟล์ Android.mk ฉันมีมัน:

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

แต่ควรมีสิ่งนี้:

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

สังเกตรายละเอียด+ =แทน: =

ฉันหวังว่าจะช่วยได้


2
หรือคุณสามารถเพิ่มทั้งหมดในบรรทัดเดียวหรือใช้อักขระแบ่งบรรทัด "\"
IgorGanapolsky

6

เรียกว่า extern "C" ตามที่ให้ไว้ในตัวอย่าง Studio ที่สร้างขึ้นโดยอัตโนมัติ แต่ลืมห่อไฟล์ที่เหลือทั้งหมดรวมถึงฟังก์ชันต่อไปนี้ไว้ในวงเล็บ {} ฟังก์ชันแรกเท่านั้นที่ใช้งานได้


4

เหตุผลเพิ่มเติม: ใช้ LOCAL_WHOLE_STATIC_LIBRARIES แทน LOCAL_STATIC_LIBRARIES ใน android.mk สิ่งนี้จะหยุดไลบรารีจากการเพิ่มประสิทธิภาพการเรียก API ที่ไม่ได้ใช้เนื่องจาก NDK ไม่สามารถตรวจพบการใช้การผูกเนทีฟจากโค้ดจาวา


1
ความแตกต่างอยู่ตรงไหน: "ใช้ LOCAL_WHOLE_STATIC_LIBRARIES แทน LOCAL_STATIC_LIBRARIES ใน android.mk"
Josh

4

มีตัวอย่าง cpp ใต้แอพใน ndk: https://github.com/android/ndk-samples/blob/master/hello-gl2/app/src/main/cpp/gl_code.cpp


2
คุณสามารถค้นหาไฟล์ cpp ใน android-ndk / samples / hello-gl2 ซึ่งเป็นส่วนหนึ่งของการแจกจ่าย Android NDK
Yenchi


1
@pevik มันตายอีกแล้ว
Mygod


ลิงค์ตายอีกแล้ว
user13107

2

ใช้ javah (ส่วนหนึ่งของ Java SDK) เป็นเครื่องมือสำหรับสิ่งนี้ (สร้างส่วนหัว. h จากไฟล์. class)


2

หากชื่อแพ็กเกจของคุณมีอักขระ _ คุณควรเขียน 1 (หนึ่ง) หลัง _ อักขระดังที่แสดงด้านล่าง:

MainActivity.java

package com.example.testcpp_2;

native-lib.cpp

JNICALL
Java_com_example_testcpp_12_MainActivity_stringFromJNI(

0

ฉันลองใช้วิธีแก้ไขปัญหาข้างต้นทั้งหมด แต่ไม่มีใครสามารถแก้ไขข้อผิดพลาดในการสร้างของฉันได้ (jni java.lang.Uns พอใจLinkError: ไม่พบการใช้งานสำหรับ ... add_library segement (valid.cpp สร้างโดยอัตโนมัติโดย Ctrl + Enter short key หรือชื่อไฟล์อื่น) หวังว่าคำตอบของฉันจะช่วยได้บ้าง

สภาพแวดล้อมการสร้างของฉัน: Gradle + CMake


0

ฉันประสบปัญหาเดียวกันและในกรณีของฉันสาเหตุคือฉันมีขีดล่างในชื่อแพ็กเกจ "RFID_Test" ฉันเปลี่ยนชื่อแพ็กเกจและใช้งานได้ ขอบคุณ user1222021


-3

ฉันประสบปัญหาเดียวกันสองครั้ง เกิดขึ้นโทรศัพท์ที่ฉันพยายามเริ่มแอปจาก Android Studio ใช้ระดับ APIที่ฉันยังไม่ได้ดาวน์โหลดใน Android Studio

  1. อัปเกรด Android Studio เป็นเวอร์ชันล่าสุด
  2. ดาวน์โหลด API ที่จำเป็นจากใน Android Studio
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.