Android NDK C ++ JNI (yerel için uygulama bulunamadı…)


89

NDK'yı C ++ ile kullanmaya çalışıyorum ve yöntem adlandırma kuralını doğru alamıyorum. benim yerel yöntemim aşağıdaki gibidir:

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

extern "C" {} 'ye sarılmış bir başlık ile.

Her şey iyi derlenir, bir .so dosyası oluşturur ve projem altındaki libs klasörüne kopyalanır, ancak Eclipse'de hata ayıklayıp çalıştırdığımda, "yerel için hiçbir uygulama bulunamadı ..." şeklinde bir günlük cat mesajı almaya devam ediyorum. Tüm NDK örnekleri C'de olduğu için kaçırdığım bir şey var mı?

Teşekkürler.


JNI koçanlarınızı kullanarak javahmı oluşturuyorsunuz ? Değilse, olmalısın. :-P
Chris Jester-Young

7
Büyük olasılıkla aramamış olduğunuz içinSystem.loadLibrary
IgorGanapolsky

1
Sorunuz için teşekkürler. Bugün yeni bir şey öğrendim.
Shady Mohamed Sherif

Yanıtlar:


151

"Hiçbir uygulama bulunmamasına" yol açabilecek birkaç şey vardır. Biri işlev prototip adını yanlış alıyor, diğeri .so dosyasını hiç yüklemiyor. System.loadLibrary()Yöntem kullanılmadan önce çağrıldığından emin misiniz ?

Eğer JNI_OnLoadtanımlanmış bir fonksiyonunuz yoksa, sadece lib'in başarılı bir şekilde çekildiğini doğrulamak için bir tane oluşturup bir günlük mesajı yazmasını isteyebilirsiniz.

En yaygın sorundan zaten kaçtınız - kullanmayı unutmak extern "C"- yani ya yukarıdaki ya da bazı küçük yazım hataları. Java beyanı neye benziyor?


14
İsa! Bana saatler değerinde işten tasarruf ettin - bunu okuduktan sonra, loadLibrary çağrımın yorumlandığını hatırlamıştım ...
zeboidlund

11
Sen de beni kurtardın! İşlev adımı ve birkaç başka şeyi dört kez kontrol ettim ... ama "C" haricini unuttum ve soruda bunu fark etmedim bile!
Qwertie


2
ayrıca kimsenin bahsetmediği bir durum vardır: altçizgiler paket ayırıcı olarak yorumlandığı için işlev adlarında '_' (alt çizgi) kullanamazsınız. Bu nedenle, yalnızca deve durumu işlevi adları mümkündür
Nulik

2
@Nulik: Eğer eğer '_' kullanabilirsiniz ondan kaçmak olarak "_1".
1818, 05

18

Bu hatanın ek bir nedeni: dekore edilmemiş yerel yöntem adınız alt çizgi içermemelidir!

Örneğin, adlı bir C işlevini dışa aktarmak istedim AudioCapture_Ping(). İşte C'deki ihracat beyannamem:

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

Java sınıfım işlevi içe aktarıyordu:

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

Alt çizgiyi kaldırana kadar Android'in yerel yöntemime dinamik olarak bağlanmasını sağlayamadım:

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 dili bildiriminde "_" ifadeleri yerel bildirimde "_1" ile değiştirilmelidir. Docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/… 'deki tablo 2-1'e bakın .
fadden

1
Çok açık, yine de birkaç saat hata ayıkladıktan sonra kendi başıma çözemedim ... Teşekkürler, beni kurtardın!
George Atsev

@ user1222021 Bir sorum var, projedeki tüm aktiviteler için cpp metodunu dışa aktarabilir miyiz, .cpp dosyasındaki metot içerisinde aktivite adını belirtmemiz gerekiyor mu?
Balflear

14

Aynı sorunu yaşadım, ancak bana göre hata Android.mk dosyasındaydı. Ona sahiptim:

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

ama şuna sahip olmalı:

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

ayrıntıyı not edin + = bunun yerine : =

Umarım bu yardımcı olur.


2
Veya hepsini tek bir satıra ekleyebilir veya `\` satır sonu karakterini kullanabilirsiniz.
IgorGanapolsky

6

Otomatik olarak oluşturulan Studio örneğinde belirtildiği gibi "C" olarak adlandırıldı, ancak aşağıdaki işlevler de dahil olmak üzere dosyanın geri kalanını {} parantez içine almayı unuttum. Yalnızca ilk işlev çalıştı.


4

Ek bir neden: android.mk'de LOCAL_STATIC_LIBRARIES yerine LOCAL_WHOLE_STATIC_LIBRARIES kullanın. Bu, kitaplığın kullanılmayan API çağrılarını optimize etmesini durdurur çünkü NDK, java kodundan yerel bağlamaların kullanımını algılayamaz.


1
"Android.mk'de LOCAL_STATIC_LIBRARIES yerine LOCAL_WHOLE_STATIC_LIBRARIES kullanın"
Josh


2

Javah (Java SDK'nın bir parçası) kullanın. Tam olarak bunun için bir araçtır (.class dosyasından .h başlığı oluşturur).


2

Paket adınız _ karakter içeriyorsa, aşağıda gösterildiği gibi _ karakterden sonra 1 (bir) yazmalısınız:

MainActivity.java

package com.example.testcpp_2;

native-lib.cpp

JNICALL
Java_com_example_testcpp_12_MainActivity_stringFromJNI(

0

Yukarıdaki tüm çözümleri deniyorum, ancak kimse derleme hatamı çözemiyor (jni java.lang.UnsatisfiedLinkError: Hiçbir uygulama bulunamadı ...), sonunda doğrulama.cpp kaynak dosyamı CMakeList.txt'ye eklemeyi unuttuğumu fark ettim add_library segmenti (doğrulama.cpp, Ctrl + Enter kısa tuşu, belki başka bir dosya adı ile otomatik olarak oluşturulur), umarım yanıtım birisine yardımcı olabilir.

derleme ortamım: Gradle + CMake


0

Aynı sorunla karşılaştım ve benim durumumda bunun nedeni, paket adında "RFID_Test" alt çizgi olmasıydı Paketi yeniden adlandırdım ve işe yaradı. Teşekkürler user1222021


-3

Aynı problemle iki kez karşılaştım. Uygulamayı Android Studio'dan başlatmaya çalıştığım telefon, Android Studio'da henüz indirmediğim bir API seviyesi kullandı .

  1. Android Studio'yu en son sürüme yükseltin
  2. Gerekli API'yi Android Studio'nun içinden indirin
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.