使用AndroidStudio进行JNI开发时,编写好了Native方法的java文件,使用javah生成头文件报错:
image.png
先上解决方案
修改javah的-classpath
参数
我原来的是:
-classpath . -jni -encoding UTF-8 -d $ModuleFileDir$/src/main/cpp/include $FileClass$
修改为:
-classpath D:\Android\Sdk\platforms\android-28\android.jar;. -jni -encoding UTF-8 -d $ModuleFileDir$/src/main/cpp/include $FileClass$
一定要注意:D:\Android\Sdk\platforms\android-28\android.jar;.
分号后面带一个英文句号。
另外,类似的问题该方法通用
其实还有一种解决方案(不推荐):
就是修改Java代码,把Surface类型改为Object
类型,只不过要自己做一些类型转换的工作,增加了代码工作量。
原因分析
我们应该知道,javah生成头文件需要给方法生成签名,而签名的原理是依据类的完整包名来的,所以究其原因是javah的-classpath
参数配置错误,导致找不到Surface类。
我们先来看一下javah的用法:
C:\Users\bian>javah 用法: javah [options] <classes> 其中, [options] 包括: -o <file> 输出文件 (只能使用 -d 或 -o 之一) -d <dir> 输出目录 -v -verbose 启用详细输出 -h --help -? 输出此消息 -version 输出版本信息 -jni 生成 JNI 样式的标头文件 (默认值) -force 始终写入输出文件 -classpath <path> 从中加载类的路径 -cp <path> 从中加载类的路径 -bootclasspath <path> 从中加载引导类的路径 <classes> 是使用其全限定名称指定的 (例如, java.lang.Object)。
-d 和-o
这两个参数用于设置生成的C\C++头文件的指定,该两参数选项不能同时使用,-d是为中的每个有JNI方法的java类都生成一个头文件,并存放在-d指定的目录中,-o则是生成的所有JNI方法的头文件都放在-o指定的文件中。
-jni
表示用于生成JNI风格的C\C++头文件,默认该参数就是开启的。
-classpath
使用-classpath后JDK将不再使用CLASSPATH中的类搜索路径,如果-classpath和CLASSPATH都没有设置,则JDK使用当前路径(.)作为类搜索路径。
推荐使用-classpath来定义JDK要搜索的类路径,而不要使用环境变量CLASSPATH的搜索路径,以减少多个项目同时使用CLASSPATH时存在的潜在冲突。例如应用1要使用a1.0.jar中的类G,应用2要使用 a2.0.jar中的类G,a2.0.jar是a1.0.jar的升级包,当a1.0.jar,a2.0.jar都在CLASSPATH中,JDK搜索到第一个包中的类G时就停止搜索,如果应用1应用2的虚拟机都从CLASSPATH中搜索,就会有一个应用得不到正确版本的类G。
-verbose
该参数,将显示javah命令搜索和装置类文件的详细过程。
仔细看-classpath
参数的解释就明白了吧,原来是我之前的classpath .
是从当前路径.
开始查找类的,当前类是哪里呢?从前面的图片中写出来了,是jre环境C:\Android\AndroidStudio\jre/bin/javah
,所以只能找到java类,不能找到安卓的类。我们把安卓SDK路径添加进去那么javah就能够找到了。
还要注意classpath的配置语法,多个路径使用分号;
隔开,所以解决方案就是前面所说的配置-classpath
参数为D:\Android\Sdk\platforms\android-28\android.jar;.
总结
根据javah生成头文件的原理我们可以知道,任何参与JNI的类,都必须知道完整的包名路径。再假设我们使用了第三方库,有一些自定义的类,那么我们也应该把这个类的路径配置到-classpath
参数中去。