發現網上很多JNI的使用教程,也很詳細,不過有的地方有些缺漏,導致很多小問題難以解決的,今天就來總結一下。
准備工作:下載NDK。
簡單的說,要用到C/C++,就要用NDK。直接百度搜索然后去官網下載就行,位置可以隨便放。
1、新建一個類,聲明native方法。這個類是java與C/C++交互的中介,方法由java聲明,由C/C++實現。
不在Activity類里面寫是為了避免編譯時報錯:找不到android.support.v7.app.AppCompatActivity
public class myJNI {
//加載so庫 static { System.loadLibrary("JniTest"); } //native方法 public static native String sayHello(); }
2、打開android studio終端,使用javac編譯上述文件,生成class文件。
命令:
D:\AndroidStudioProject\testJNI\app\src\main\java\com\example\binbin\testjni>javac myJNI.java
3、確認自己類的包名!然后在上一級的位置使用javah生成.h頭文件
一定要在上一級哦,不然不會報錯:找不到xxx類
比如我的myJNI.class在
D:\AndroidStudioProject\testJNI\app\src\main\java\com\example\binbin\testjni
我的包名是:
package com.example.binbin.testjni;
所以我的javah命令應該這么寫:
D:\AndroidStudioProject\testJNI\app\src\main\java>javah -jni com.example.binbin.testjni.myJNI
然后就能看到生成了一個h文件。
4、新建一個jni文件夾,新建main.c,把.h里面的內容復制進去,並實現里面的函數。
生成的h文件
/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class com_example_binbin_testjni_myJNI */ #ifndef _Included_com_example_binbin_testjni_myJNI #define _Included_com_example_binbin_testjni_myJNI #ifdef __cplusplus extern "C" { #endif /* * Class: com_example_binbin_testjni_myJNI * Method: sayHello * Signature: ()Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_com_example_binbin_testjni_myJNI_sayHello (JNIEnv *, jclass); #ifdef __cplusplus } #endif #endif
拷貝修改后的main.c
/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class com_example_binbin_testjni_myJNI */ #ifndef _Included_com_example_binbin_testjni_myJNI #define _Included_com_example_binbin_testjni_myJNI #ifdef __cplusplus extern "C" { #endif /* * Class: com_example_binbin_testjni_myJNI * Method: sayHello * Signature: ()Ljava/lang/String; */
//就實現了個函數 JNIEnv的用法可以自行百度,這里就不展開了 JNIEXPORT jstring JNICALL Java_com_example_binbin_testjni_myJNI_sayHello (JNIEnv *env, jclass jobj){
//返回一句話 return (*env)->NewStringUTF(env,"JNI hahahahahahahaha"); } #ifdef __cplusplus } #endif #endif
還要在jni文件夾下添加一個空白的util.c文件,不然會報錯,我也不知道為什么。
5、配置NDK
打開Project的local.properties文件添加NDK路徑
打開app Module的build.gradle文件,在defaultConfig節點里添加以下代碼
注意這里的moduleName,是我們在之前自己編寫的類里面加載的so庫名
ndk { moduleName "JniTest" ldLibs "log", "z", "m" abiFilters "armeabi", "armeabi-v7a", "x86" }
還要在gradle.properties里面加上這么一句話:
android.useDeprecatedNdk=true
6、生成SO庫
完成以上步驟之后,我們rebuild一下就可以生成so庫了
在項目的app\build\intermediates\ndk\debug\lib路徑下
7、配置so庫
在src\main下新建文件夾jniLIB,並將生成的SO文件拷貝到該文件夾下
8、使用JNI
因為native方法聲明成了靜態的方法,在Activity里面直接調用myJNI類就行
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); text = (TextView)findViewById(R.id.text);
//調用 text.setText(myJNI.sayHello()); } }
ok!
總結一下流程:
編寫靜態方法(用java聲明)-->編譯生成class文件--->編譯生成h文件---->編寫C文件(用C/C++實現)
---->配置NDK---->配置so庫---->在Activity調用(Java調用C/C++)。
android studio雖然很多小問題,但也算很方便了,mk文件編輯器幫你弄好了,直接可以生成so庫。