"No implementation found for" 使用 NativeActivity
"No implementation found for" using NativeActivity
我有一个正在处理的项目,它使用 NativeActivity,连同 android_native_app_glue 文件连接到 Java 端。我需要通过 Java 访问一些非 NDK classes 并且已经弄清楚如何从 C 调用 Java,但是我遇到了相反的问题。当从 Java 调用 C 时,我得到 "No implementation found for etc...",我已经检查了这种调用的大部分陷阱,并相信一切都是正确的。这里是 Activity class.
package com.JNITest;
import android.app.NativeActivity;
import android.util.Log;
public class JniNativeActivity extends NativeActivity
{
private static String TAG = "JniNativeActivity";
public static native void nativeJniCall();
public JniNativeActivity()
{
super();
Log.v(TAG, "Creating JniNativeActivity");
}
public void testCall()
{
Log.v(TAG, "Calling native");
nativeJniCall();
}
}
因为这是使用胶水代码的原生Activity,所以没有调用 JNI_OnLoad,入口点是 android_main(胶水代码已设置为 运行 在它自己的线程中)。
void android_main(struct android_app* state)
{
test_call(state->activity);
etc...
}
...
void test_call(ANativeActivity *activity)
{
JNIEnv *jni;
activity->vm->AttachCurrentThread(&jni, NULL);
jclass activityClass=jni->GetObjectClass(activity->clazz);
jmethodID testCallId=jni->GetMethodID(activityClass, "testCall", "()V");
jni->CallVoidMethod(activity->clazz, testCallId);
}
extern "C"
{
JNIEXPORT void JNICALL Java_com_JNITest_JniNativeActivity_nativeJniCall(JNIEnv *, jclass)
{
LOGI("nativeJniCall");
}
}
来自 logcat
...
waiting for debugger to settle...
waiting for debugger to settle...
debugger has settled (1388)
Creating JniNativeActivity
Creating: 0xb420b100
Config: mcc=0 mnc=0 lang=en cnt=US orien=2 touch=3 dens=576 keys=2 nav=1 keysHid=1 navHid=0 sdk=22 size=2 long=1 modetype=1 modenight=1
Start: 0xb420b100
removeObsoleteFile: deleting file=161_task.xml
Calling native
No implementation found for void com.JNITest.JniNativeActivity.nativeJniCall() (tried Java_com_JNITest_JniNativeActivity_nativeJniCall and Java_com_JNITest_JniNativeActivity_nativeJniCall__)
activityState=10
Resume: 0xb420b100
activityState=11
Adding window Window{2b21e24c u0 com.JNITest/com.JNITest.JniNativeActivity} at 2 of 8 (before Window{3238fdec u0 Starting com.JNITest})
InputQueueCreated: 0xb420b100 -- 0xb420b880
APP_CMD_INPUT_CHANGED
Attaching input queue to looper
NativeWindowCreated: 0xb420b100 -- 0xb417ae08
APP_CMD_INIT_WINDOW
Waiting for host to establish connection
WindowFocusChanged: 0xb420b100 -- 1
Accepting new connection from local client
Accepted new client connection: PID = 3945, fd = 39
Requesting connection from host
Sending initiation request to host
Accepting new connection from host service
Accepted new host connection: fd = 40
Connecting local socket 39 to host socket 40
HostConnection::get() New Host Connection established 0xb4272e50, tid 3976
Displayed com.JNITest/.JniNativeActivity: +5s618ms
任何 运行s 都意味着库已加载,它也在日志中
...
=thread-created,id="9",group-id="i1"[New Thread 3958]
=thread-created,id="10",group-id="i1"[New Thread 3959]
=thread-created,id="11",group-id="i1"[New Thread 3960]
Loaded 'D:\projects\JNITest\JNITest\JNITest.Android.NativeActivity\x86\Debug\libJNITest.so'
=thread-created,id="12",group-id="i1"[New Thread 3976]
[Switching to Thread 3976]
=thread-created,id="13",group-id="i1"[New Thread 3975]
Loaded 'gralloc.donatello.so'
...
我已经用 javah 验证了它的名字
extern "C" {
#endif
/*
* Class: com_JNITest_JniNativeActivity
* Method: nativeJniCall
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_com_JNITest_JniNativeActivity_nativeJniCall
(JNIEnv *, jclass);
#ifdef __cplusplus
}
#endif
我也检查了库externs,函数在那里
...
U glRotatef
U glShadeModel
U glTranslatef
U glVertexPointer
U glViewport
00007004 D indices
00004b70 T Java_com_JNITest_JniNativeActivity_nativeJniCall
U malloc
U memcpy
U memset
U pipe
...
我在另一个项目中遇到了这个问题并创建了一个测试应用程序(上面的代码来自那里)所以它不是一些随机的独特配置问题。我对此有点不知所措,我假设它与 NativeActivity 和胶水代码(可能是线程)有一些问题,但不确定如何解决它。任何帮助将不胜感激。
好的,我发现了问题。似乎在这种情况下,因为 System.loadlibrary 没有与胶水代码一起使用,所以标准查找机制不起作用。您必须手动调用 RegisterNatives(从有效的 JNIEnv)。因此,对于这种情况,您需要执行以下操作:
void nativeJniCall(JNIEnv *, jclass)
{
LOGV("nativeJniCall");
}
void android_main(struct android_app* state)
{
test_call(state->activity);
etc...
}
...
void test_call(ANativeActivity *activity)
{
JNIEnv *jni;
activity->vm->AttachCurrentThread(&jni, NULL);
jclass activityClass=jni->GetObjectClass(activity->clazz);
jmethodID testCallId=jni->GetMethodID(activityClass, "testCall", "()V");
JNINativeMethod methodTable[]=
{
{"nativeJniCall", "()V", (void *)nativeJniCall}
};
int methodTableSize=sizeof(methodTable)/sizeof(methodTable[0]);
jni->RegisterNatives(activityClass, methodTable, methodTableSize);
jni->CallVoidMethod(activity->clazz, testCallId);
}
对于生产,您将缓存所有 jclass/jmethoidIDs(记得使用 NewGlobalRef/DeleteGlobalRef)并且只使用 class 注册本机函数一次,但这只是一个例子。希望它可以节省其他人一些时间。
我有一个正在处理的项目,它使用 NativeActivity,连同 android_native_app_glue 文件连接到 Java 端。我需要通过 Java 访问一些非 NDK classes 并且已经弄清楚如何从 C 调用 Java,但是我遇到了相反的问题。当从 Java 调用 C 时,我得到 "No implementation found for etc...",我已经检查了这种调用的大部分陷阱,并相信一切都是正确的。这里是 Activity class.
package com.JNITest;
import android.app.NativeActivity;
import android.util.Log;
public class JniNativeActivity extends NativeActivity
{
private static String TAG = "JniNativeActivity";
public static native void nativeJniCall();
public JniNativeActivity()
{
super();
Log.v(TAG, "Creating JniNativeActivity");
}
public void testCall()
{
Log.v(TAG, "Calling native");
nativeJniCall();
}
}
因为这是使用胶水代码的原生Activity,所以没有调用 JNI_OnLoad,入口点是 android_main(胶水代码已设置为 运行 在它自己的线程中)。
void android_main(struct android_app* state)
{
test_call(state->activity);
etc...
}
...
void test_call(ANativeActivity *activity)
{
JNIEnv *jni;
activity->vm->AttachCurrentThread(&jni, NULL);
jclass activityClass=jni->GetObjectClass(activity->clazz);
jmethodID testCallId=jni->GetMethodID(activityClass, "testCall", "()V");
jni->CallVoidMethod(activity->clazz, testCallId);
}
extern "C"
{
JNIEXPORT void JNICALL Java_com_JNITest_JniNativeActivity_nativeJniCall(JNIEnv *, jclass)
{
LOGI("nativeJniCall");
}
}
来自 logcat
...
waiting for debugger to settle...
waiting for debugger to settle...
debugger has settled (1388)
Creating JniNativeActivity
Creating: 0xb420b100
Config: mcc=0 mnc=0 lang=en cnt=US orien=2 touch=3 dens=576 keys=2 nav=1 keysHid=1 navHid=0 sdk=22 size=2 long=1 modetype=1 modenight=1
Start: 0xb420b100
removeObsoleteFile: deleting file=161_task.xml
Calling native
No implementation found for void com.JNITest.JniNativeActivity.nativeJniCall() (tried Java_com_JNITest_JniNativeActivity_nativeJniCall and Java_com_JNITest_JniNativeActivity_nativeJniCall__)
activityState=10
Resume: 0xb420b100
activityState=11
Adding window Window{2b21e24c u0 com.JNITest/com.JNITest.JniNativeActivity} at 2 of 8 (before Window{3238fdec u0 Starting com.JNITest})
InputQueueCreated: 0xb420b100 -- 0xb420b880
APP_CMD_INPUT_CHANGED
Attaching input queue to looper
NativeWindowCreated: 0xb420b100 -- 0xb417ae08
APP_CMD_INIT_WINDOW
Waiting for host to establish connection
WindowFocusChanged: 0xb420b100 -- 1
Accepting new connection from local client
Accepted new client connection: PID = 3945, fd = 39
Requesting connection from host
Sending initiation request to host
Accepting new connection from host service
Accepted new host connection: fd = 40
Connecting local socket 39 to host socket 40
HostConnection::get() New Host Connection established 0xb4272e50, tid 3976
Displayed com.JNITest/.JniNativeActivity: +5s618ms
任何 运行s 都意味着库已加载,它也在日志中
...
=thread-created,id="9",group-id="i1"[New Thread 3958]
=thread-created,id="10",group-id="i1"[New Thread 3959]
=thread-created,id="11",group-id="i1"[New Thread 3960]
Loaded 'D:\projects\JNITest\JNITest\JNITest.Android.NativeActivity\x86\Debug\libJNITest.so'
=thread-created,id="12",group-id="i1"[New Thread 3976]
[Switching to Thread 3976]
=thread-created,id="13",group-id="i1"[New Thread 3975]
Loaded 'gralloc.donatello.so'
...
我已经用 javah 验证了它的名字
extern "C" {
#endif
/*
* Class: com_JNITest_JniNativeActivity
* Method: nativeJniCall
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_com_JNITest_JniNativeActivity_nativeJniCall
(JNIEnv *, jclass);
#ifdef __cplusplus
}
#endif
我也检查了库externs,函数在那里
...
U glRotatef
U glShadeModel
U glTranslatef
U glVertexPointer
U glViewport
00007004 D indices
00004b70 T Java_com_JNITest_JniNativeActivity_nativeJniCall
U malloc
U memcpy
U memset
U pipe
...
我在另一个项目中遇到了这个问题并创建了一个测试应用程序(上面的代码来自那里)所以它不是一些随机的独特配置问题。我对此有点不知所措,我假设它与 NativeActivity 和胶水代码(可能是线程)有一些问题,但不确定如何解决它。任何帮助将不胜感激。
好的,我发现了问题。似乎在这种情况下,因为 System.loadlibrary 没有与胶水代码一起使用,所以标准查找机制不起作用。您必须手动调用 RegisterNatives(从有效的 JNIEnv)。因此,对于这种情况,您需要执行以下操作:
void nativeJniCall(JNIEnv *, jclass)
{
LOGV("nativeJniCall");
}
void android_main(struct android_app* state)
{
test_call(state->activity);
etc...
}
...
void test_call(ANativeActivity *activity)
{
JNIEnv *jni;
activity->vm->AttachCurrentThread(&jni, NULL);
jclass activityClass=jni->GetObjectClass(activity->clazz);
jmethodID testCallId=jni->GetMethodID(activityClass, "testCall", "()V");
JNINativeMethod methodTable[]=
{
{"nativeJniCall", "()V", (void *)nativeJniCall}
};
int methodTableSize=sizeof(methodTable)/sizeof(methodTable[0]);
jni->RegisterNatives(activityClass, methodTable, methodTableSize);
jni->CallVoidMethod(activity->clazz, testCallId);
}
对于生产,您将缓存所有 jclass/jmethoidIDs(记得使用 NewGlobalRef/DeleteGlobalRef)并且只使用 class 注册本机函数一次,但这只是一个例子。希望它可以节省其他人一些时间。