今天帮朋友搞了一天eclipse导入jni项目报错,之前一直以为是C文件写错了,后来发现是ndk一直配置不上,导致一个.so文件一直没生成,编译时找不到
网上Usb Audio项目导入出错
报错为:
03-27 12:18:41.591: E/AndroidRuntime(8831): FATAL EXCEPTION: main
03-27 12:18:41.591: E/AndroidRuntime(8831): Process: au.id.jms.usbaudiodemo, PID: 8831
03-27 12:18:41.591: E/AndroidRuntime(8831): java.lang.RuntimeException: Unable to instantiate activity ComponentInfo{au.id.jms.usbaudiodemo/au.id.jms.usbaudiodemo.MainActivity}: java.lang.ClassNotFoundException: Didn't find class "au.id.jms.usbaudiodemo.MainActivity" on path: DexPathList[[zip file "/data/app/au.id.jms.usbaudiodemo-1/base.apk"],nativeLibraryDirectories=[/vendor/lib64, /system/lib64]]
03-27 12:18:41.591: E/AndroidRuntime(8831): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2574)
03-27 12:18:41.591: E/AndroidRuntime(8831): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2732)
03-27 12:18:41.591: E/AndroidRuntime(8831): at android.app.ActivityThread.access$900(ActivityThread.java:186)
03-27 12:18:41.591: E/AndroidRuntime(8831): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1583)
03-27 12:18:41.591: E/AndroidRuntime(8831): at android.os.Handler.dispatchMessage(Handler.java:111)
03-27 12:18:41.591: E/AndroidRuntime(8831): at android.os.Looper.loop(Looper.java:199)
03-27 12:18:41.591: E/AndroidRuntime(8831): at android.app.ActivityThread.main(ActivityThread.java:5848)
03-27 12:18:41.591: E/AndroidRuntime(8831): at java.lang.reflect.Method.invoke(Native Method)
03-27 12:18:41.591: E/AndroidRuntime(8831): at java.lang.reflect.Method.invoke(Method.java:372)
03-27 12:18:41.591: E/AndroidRuntime(8831): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1003)
03-27 12:18:41.591: E/AndroidRuntime(8831): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:798)
03-27 12:18:41.591: E/AndroidRuntime(8831): Caused by: java.lang.ClassNotFoundException: Didn't find class "au.id.jms.usbaudiodemo.MainActivity" on path: DexPathList[[zip file "/data/app/au.id.jms.usbaudiodemo-1/base.apk"],nativeLibraryDirectories=[/vendor/lib64, /system/lib64]]
03-27 12:18:41.591: E/AndroidRuntime(8831): at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56)
03-27 12:18:41.591: E/AndroidRuntime(8831): at java.lang.ClassLoader.loadClass(ClassLoader.java:511)
03-27 12:18:41.591: E/AndroidRuntime(8831): at java.lang.ClassLoader.loadClass(ClassLoader.java:469)
03-27 12:18:41.591: E/AndroidRuntime(8831): at android.app.Instrumentation.newActivity(Instrumentation.java:1074)
03-27 12:18:41.591: E/AndroidRuntime(8831): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2564)
03-27 12:18:41.591: E/AndroidRuntime(8831): ... 10 more
03-27 12:18:41.591: E/AndroidRuntime(8831): Suppressed: java.lang.NoClassDefFoundError: au.id.jms.usbaudiodemo.MainActivity
03-27 12:18:41.591: E/AndroidRuntime(8831): at dalvik.system.DexFile.defineClassNative(Native Method)
03-27 12:18:41.591: E/AndroidRuntime(8831): at dalvik.system.DexFile.defineClass(DexFile.java:226)
03-27 12:18:41.591: E/AndroidRuntime(8831): at dalvik.system.DexFile.loadClassBinaryName(DexFile.java:219)
03-27 12:18:41.591: E/AndroidRuntime(8831): at dalvik.system.DexPathList.findClass(DexPathList.java:321)
03-27 12:18:41.591: E/AndroidRuntime(8831): at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:54)
03-27 12:18:41.591: E/AndroidRuntime(8831): ... 14 more
03-27 12:18:41.591: E/AndroidRuntime(8831): Suppressed: java.lang.ClassNotFoundException: au.id.jms.usbaudiodemo.MainActivity
03-27 12:18:41.591: E/AndroidRuntime(8831): at java.lang.Class.classForName(Native Method)
03-27 12:18:41.591: E/AndroidRuntime(8831): at java.lang.BootClassLoader.findClass(ClassLoader.java:781)
03-27 12:18:41.591: E/AndroidRuntime(8831): at java.lang.BootClassLoader.loadClass(ClassLoader.java:841)
03-27 12:18:41.591: E/AndroidRuntime(8831): at java.lang.ClassLoader.loadClass(ClassLoader.java:504)
03-27 12:18:41.591: E/AndroidRuntime(8831): ... 13 more
03-27 12:18:41.591: E/AndroidRuntime(8831): Caused by: java.lang.NoClassDefFoundError: Class not found using the boot class loader; no stack available
我们在安装环境的时候安装了NDK,可以在eclipse下直接生成so文件。NDK的压缩包里面自带了一些sample工程,NDK的文件直接解压到某个目录下即可。
第一次生成so文件的时候,我们先使用NDK的sample下的hello-jni的例子。
1、启动eclipse,通过Create project from existing source,选择hello-jni的目录,按默认选项创建工程即可;
2、观察hello-jni的工程目录结构,发现根目录下多了一个名叫jni的文件夹,该文件夹下面有两个文件,Android.mk和hello-jni.c。
Android.mk是用来生成so文件的配置文件,我们来看看里面是什么:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := hello-jni
LOCAL_SRC_FILES := hello-jni.c
include $(BUILD_SHARED_LIBRARY)
include $(BUILD_SHARED_LIBRARY)表示会生成一个动态链接库,即so文件,生成的库文件名称为lib*.so
LOCAL_MODULE := hello-jni表示将要生成一个名称为libhello-jni.so的库文件
LOCAL_SRC_FILES := hello-jni.c表示生成库文件的源文件是hello-jni.c
打开hello-jni.c文件,会看到里面有一个函数:
jstring Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env, jobject thiz )
{
return (*env)->NewStringUTF(env, "Hello from JNI !");
}
这个函数从根据什么原则生成的呢?是根据src下的HelloJni.java文件中的函数 public native String stringFromJNI();生成的。命名规则为:
Java_(固定开头)com_example_hellojni(用"_"连接的包名)_HelloJni(类名)_stringFromJNI(函数名)
这个函数的生成可以使用javah的命令:用命令行方式进入工程目录的bin\classes目录下,运行javah com.example.hellojni.HelloJni,就会把所有native的函数都按规则生成在一个名为HelloJni.h的头文件里。
3、新建并配置一个新的Builder
1) 点击Project->Properties->Builders->New,新建立一个Builder。在弹出的对话框上面点击Program,点击OK;
2) 在弹出的对话框【Edit Configuration】中,配置选项卡【Main】:
Location中需要填入nkd-build.cmd的路径(NDK安装目录下)。
WorkingDiretcoty中需要填入HelloJni的工程根目录。
3) 在【EditConfiguration】中,配置选项卡【Refresh】:
勾选“Refresh resources upon completion”,
勾选“The entire workspace”,
勾选“Recuresively include sub-folders”。
4)在【EditConfiguration】中,配置选项卡【Build Options】:
勾选“After a “Clean””,
勾选“During manual builds”,
勾选“During auto builds”,
勾选“Specify working set of relevant resources”。
点击“Specify Resources…”勾选TestNDK工程的“jni“目录,Finish!
保存设置,点击OK。
4、生成so文件
由于我们勾选了“During auto builds”,所以在工程有所改变的时候,so文件便会自动编译,正确生成以后就能在工程目录下发现多了两个文件夹,文件夹libs\armeabi目录下生成了一个叫libhello-jni.so的文件。至此,使用NDK生成so文件的工作就完成了。
5、so文件的调用
在HelloJni.java文件中有一段代码:
static {
System.loadLibrary("hello-jni");
}
使用loadLibrary就可以加载该so文件了,加载的时候不需要写libhello-jni.so,只要写hello-jni就可以了。