Kotlin越来越普及和流行,我们也开始在项目中全面推广Kotlin。自然也就涉及到了JNI这一块。JNI只是Java与Native的一个中间层,但Kotlin里面使用JNI还是有一些差别。本文梳理一下希望提高开发效率
关键字external
在Java里面标识一个方法是JNI方法,使用关键字native
但在Kotlin里面使用external
关键字
生成JNI头文件javah
使用关键字external
标识该方法是JNI方法,在调用这个方时JVM会自动去调用Java_包名_类名_方法名
的c++函数。Java提供了一个工具javah
来自动生成这个头文件,当然也可以自己直接写。
通过上面的javah
帮助发现输入的是class文件,Kotlin最终也会生成class文件,可以看出javah
可以完全支持Kotlin和Java。
javah -d /*JNI 头文件输出路径*/ src/main/cpp -cp /*android-sdk路径*/ "**/platforms/android-21/android.jar: /*生成的class路径*/ build/tmp/kotlin-classes/debug" /*类的全路径*/ com.**.Class
External Tools
“NDK开发之路”介绍使用AndroidStudio开发NDK事半功倍,自然Kotlin生成头文件这种事情也可以一键搞定。首先要依赖AndroidStudio的External Tool。
打开Perferences->External Tools->add
由于AndroidStudio可以使用宏所以设置的值是通用的。
Program
/Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/javah
$JDKPath$/bin/javah
Parameters
-d src/main/cpp/ -cp "$ModuleSdkPath$/platforms/android-21/android.jar:/Applications/Android/ Studio.app/Contents/jre/jdk/Contentsjre/jdk/Contents/lib/kotlin-runtime.jar:build/tmp/kotlin-classes/debug" $FileFQPackage$.$FileNameWithoutAllExtensions$
-d src/main/cpp/ -cp "$Classpath$" $FileFQPackage$.$FileNameWithoutAllExtensions$
Working directory
$ModuleFileDir$
Usage
然后在Kotlin类里面右击选择External Tools就会自动在src/main/cpp(这个路径可以在上面的配置里面修改)
文件夹里面生成JNI头文件了
注意:build/tmp/kotlin-classes/debug是AndroidStudio生成Kotlin class文件的地方,所以每次使用External Tools的时候需要先编译项目生成class文件
JNI的两种方式
除了上面说的external
标识的方法调用c++代码。其实jni.h里面还提供一种方式
jint RegisterNatives(jclass clazz, const JNINativeMethod* methods, jint nMethods)
通过注册方式绑定Java与C++的函数关系。在JNI_OnLoad方法里面注册从而不需要编写JNI头文件,比较灵活方便,不需要每次都要生成头文件。
参考资料
Kotlin http://kotlinlang.org/docs/reference/keyword-reference.html#modifier-keywords
2019-10-21 补充更新
很多朋友留言说找不到kotlin的编译环境,一直没有空回复大家,抱歉。研究了一下手上的AndroidStudio版本,重新更新一下脚本。
1. AndroidStudio版本
Android Studio 3.3.2
Build #AI-182.5107.16.33.5314842, built on February 16, 2019
JRE: 1.8.0_152-release-1248-b01 x86_64
JVM: OpenJDK 64-Bit Server VM by JetBrains s.r.o
macOS 10.15
2. External Tools
Program
$JDKPath$/bin/javah
Parameters
-d src/main/cpp/ -cp "$Classpath$" $FileFQPackage$.$FileNameWithoutAllExtensions$
Working directory
$ModuleFileDir$