文章目录
javah 和 javap,这两个工具,都是jdk的bin目录下提供的命令,那么为什么要用这两个工具呢?
一、javah
我们知道有几个东西是很难写的,如当c++要提供一个接口给java的时候的方法名
Java_com_luminal_ndktest_Jni_getStringFromJni,很长有时候也会很容易写错,这个时候我们可以用到javah,
javah会去搜索这个类里面所有的native方法,然后会帮你生成c++方法的头文件,也就是方法声明。
1、生成 .h 文件
如我们在Android Studio的Terminal窗口输入如下命令:
//查看当前目录
//ls
//切换目录
//cd app/src/main/java/
//生成.h文件
//javah com.luminal.ndktest.Jni
如下图,它会生成一个 com_luminal_ndktest_Jni.h 的文件
com_luminal_ndktest_Jni.h 文件的内容如下,它自动帮我们生成了头文件
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_luminal_ndktest_Jni */
#ifndef _Included_com_luminal_ndktest_Jni
#define _Included_com_luminal_ndktest_Jni
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_luminal_ndktest_Jni
* Method: getStringFromJni
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_luminal_ndktest_Jni_getStringFromJni
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
我们回头做 jni/ndk 开发,把这些生成c/c++方法的头文件,也就是方法声明,复制到.cpp文件里面进行实现即可
2、把 .h 文件生成到c/c++指定目录
刚在生成的 com_luminal_ndktest_Jni.h 文件,是在java目录,它是java代码的目录,我们可以把它放到c/c++代码特有的目录,这时我们可以输入如下命令:
//删除.h文件
//rm com_luminal_ndktest_Jni.h
//指定目录生成.h文件
//javah -d ../cpp com.luminal.ndktest.Jni
如下图,在cpp目录下生成了 com_luminal_ndktest_Jni.h 文件
如果要删除 com_luminal_ndktest_Jni.h 文件,可执行如下命令
//指定目录删除.h文件
//rm ../cpp/com_luminal_ndktest_Jni.h
3、命令复习
javah 用于生成 native接口定义(在C/C++中的),比如:
javah -d ../cpp/包名+类名 即javah -d ../cpp/com.luminal.ndktest.Jni
javah -d ../cpp/ 表示你的头文件要生成到哪里去
com.luminal.ndktest.Jni 表示你的那个类里面有nativie接口
//查看当前目录
//ls
//切换目录
//cd app/src/main/java/
//生成.h文件
//javah com.luminal.ndktest.Jni
//删除.h文件
//rm com_luminal_ndktest_Jni.h
//指定目录生成.h文件
//javah -d ../cpp com.luminal.ndktest.Jni
//指定目录删除.h文件
//rm ../cpp/com_luminal_ndktest_Jni.h
二、javap
1、javap的用途
我们上面讲了javah的作用用途,那么javap是拿来干什么的?
javap用来反编译,同时用于生成java函数(方法)的签名
2、获取java方法的签名
如博文:安卓之JNI 和 NDK编程(七)c++调用java代码 中这段代码方法参数3,方法签名到底是怎么来的?
//3、获取方法(函数)
//参数1:对象名。 参数2:方法名
//参数3:方法签名。"()V" 括号表示callByCpp方法没有参数,V表示callByCpp方法没有返回值,返回值为void
jmethodID methodID = env->GetMethodID(jniclass, "callByCpp", "()V");
上面我们执行javah命令以后,它现在在java目录下,我们可以切换到项目根目录( 我的项目名称ndkCode),查找到 Jni类 (用来封装c/c++的native方法的类) 的class文件
bogon:java luminal$ cd ..
bogon:main luminal$ ls
AndroidManifest.xml cpp java res
bogon:main luminal$ cd ..
bogon:src luminal$ ls
androidTest main test
bogon:src luminal$ cd ..
bogon:app luminal$ ls
CMakeLists.txt app.iml build build.gradle libs proguard-rules.pro src
bogon:app luminal$ cd ..
bogon:ndkCode luminal$ ls
app code.iml gradle.properties gradlew.bat ndkCode.iml
build.gradle gradle gradlew local.properties settings.gradle
bogon:ndkCode luminal$ find . -name "Jni.class"
./app/build/intermediates/incremental-verifier/debug/com/luminal/ndktest/Jni.class
./app/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/luminal/ndktest/Jni.class
./app/build/intermediates/transforms/instantRun/debug/0/com/luminal/ndktest/Jni.class
上面找到三个Jni.class文件,然后我们用 javap -s 命令执行javac目录下的,即可看到相关方法的签名
javap -s app/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/luminal/ndktest/Jni.class
bogon:ndkCode luminal$ javap -s app/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/luminal/ndktest/Jni.class
Compiled from "Jni.java"
public class com.luminal.ndktest.Jni {
public com.luminal.ndktest.Jni();
descriptor: ()V
public static com.luminal.ndktest.Jni instance();
descriptor: ()Lcom/luminal/ndktest/Jni;
public native java.lang.String getStringFromJni();
descriptor: ()Ljava/lang/String;
public void callByCpp();
descriptor: ()V
static {};
descriptor: ()V
}
3、获取java方法的签名(选看)
我们也可以把三个目录的Jni.class都执行看看:
javap -s app/build/intermediates/incremental-verifier/debug/com/luminal/ndktest/Jni.class
javap -s app/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/luminal/ndktest/Jni.class
javap -s app/build/intermediates/transforms/instantRun/debug/0/com/luminal/ndktest/Jni.class
bogon:ndkCode luminal$ javap -s app/build/intermediates/incremental-verifier/debug/com/luminal/ndktest/Jni.class
Compiled from "Jni.java"
public class com.luminal.ndktest.Jni {
public com.luminal.ndktest.Jni();
descriptor: ()V
public static com.luminal.ndktest.Jni instance();
descriptor: ()Lcom/luminal/ndktest/Jni;
public native java.lang.String getStringFromJni();
descriptor: ()Ljava/lang/String;
public void callByCpp();
descriptor: ()V
static {};
descriptor: ()V
}
bogon:ndkCode luminal$ javap -s app/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/luminal/ndktest/Jni.class
Compiled from "Jni.java"
public class com.luminal.ndktest.Jni {
public com.luminal.ndktest.Jni();
descriptor: ()V
public static com.luminal.ndktest.Jni instance();
descriptor: ()Lcom/luminal/ndktest/Jni;
public native java.lang.String getStringFromJni();
descriptor: ()Ljava/lang/String;
public void callByCpp();
descriptor: ()V
static {};
descriptor: ()V
}
bogon:ndkCode luminal$ javap -s app/build/intermediates/transforms/instantRun/debug/0/com/luminal/ndktest/Jni.class
Compiled from "Jni.java"
public class com.luminal.ndktest.Jni {
public static volatile transient com.android.tools.ir.runtime.IncrementalChange $change;
descriptor: Lcom/android/tools/ir/runtime/IncrementalChange;
public static final long serialVersionUID;
descriptor: J
public com.luminal.ndktest.Jni();
descriptor: ()V
public static com.luminal.ndktest.Jni instance();
descriptor: ()Lcom/luminal/ndktest/Jni;
public native java.lang.String getStringFromJni();
descriptor: ()Ljava/lang/String;
public void callByCpp();
descriptor: ()V
public static {};
descriptor: ()V
public static java.lang.Object access$super(com.luminal.ndktest.Jni, java.lang.String, java.lang.Object...);
descriptor: (Lcom/luminal/ndktest/Jni;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/Object;
com.luminal.ndktest.Jni(java.lang.Object[], com.android.tools.ir.runtime.InstantReloadException);
descriptor: ([Ljava/lang/Object;Lcom/android/tools/ir/runtime/InstantReloadException;)V
}
bogon:ndkCode luminal$
4、AS插件获取java方法的签名
在jni/ndk开发的时候,经常要看一个方法的方法签名,我们讲了可以用命令行来查看,下面我们将讲讲在AS之下有一个插件,可以很方便地在AS内查看java方法的签名,打开Android Studio->Preferences->Plugins,点击下面的Browse respositories,搜索jclasslib,如下图,当然由于我的ide最近更新到AndroidStudio 3.5,它如下图:
其它可参考博文:
安卓开发学习之在Android Studio下查看java类的字节码
https://blog.csdn.net/qq_37475168/article/details/80391821
5、命令复习
//返回上一个目录
//cd ..
//搜索目录下的某个文件
//find -name "Jni.class" //【此命令在mac上有误】
//find . -name "Jni.class" //【mac能使用】
//获取java方法签名
javap -s xxx.class