这一篇主要内容是Native调用java方法和Native调用Android API,以及External Tools快速生成.h文件,依然是使用NDK方式编译,如果是复制粘贴党,建议跟本文用一样的工程名,本文后面会提供demo链接
一、创建工程
1.创建名为Jnitest01的工程
2.点击Next 选择API等级,我选择的是26,Activity选择Empty Activity,一路next后点击Finish创建工程
二、创建Myjni类并编写load与Native接口
1.创建Myjni类
填写类名并点击OK
2.为Myjni类添加代码
代码:
public class Myjni { private Context lContext; static { System.loadLibrary("Myjni"); } public Myjni(Context context){ this.lContext = context; } public void MyToast(String s) { Toast.makeText(lContext, s, Toast.LENGTH_SHORT).show(); } //native public native void MyjniToast(String s); //native public static native void NativeToast(Context context, String s); //native public static native String NativeString(); }
三、配置External tools快速生成.h头文件
1.打开External对话框
在菜单栏找到 File->Settings..->
然后找到 Tools->External tools点击添加Tool按钮
2.设置tool信息
不愿意添加宏照抄即可,需要注意的是Android SDK 的JAR包路径要根据自己的路径修改以下
Name:Javah
Description:Javah
Program:$JDKPath$\bin\javah
Parameters:-d jni -classpath D:\Android\android-sdk\platforms\android-19\\android.jar;$OutputPath$ $FileClass$
这里需要特别注意一下 D:\Android\android-sdk\platforms\android-19\\android.jar 这个SDK包的位置请根据自己的机器环境填写 否则会发生错误)
Working directory:$ProjectFileDir$
设置完毕点击OK即可
3. Make Project生成class文件
点击Make Project后会在工程路径 \app\build\intermediates\classes\debug\com\example\file\jnitest01 中生成出class文件,
下面生成头文件需要class文件
4.使用tool生成头文件
点击 javah 后会开始自动生成,生成成功会提示处理完成 错误为0个
由于宏设置的工作目录在工程的根目录,所以头文件会生成在工程根目录下面的jni文件夹中,
比如的我工程目录在 D:\AndroidStudioProjects\Jnitest01 ,那么在头文件会生成在 D:\AndroidStudioProjects\Jnitest01\jni 中
四、编写native代码
1.在Java目录下新建Jni文件夹
2.把上面生成的com_example_file_test01_Myjni.h 移动到新建的jni目录下
3.在jni目录下新建一个cpp文件名为Myjni.cpp
点击OK创建即可
4.为新建的Myjni.cpp编写native代码
由于代码有点长就不截图了,直接上代码
// Created by file on 2017/10/24.
#include
#include
#define LOG_TAG "native-dev"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
JNIEXPORT void JNICALL Java_com_example_file_jnitest01_Myjni_MyjniToast
(JNIEnv* env, jobject job, jstring jStr)
{
jclass myjniclass = NULL;
jmethodID mid = NULL;
const char* pNativeStr = NULL;
jstring szOut = NULL;
LOGI("MyjniToast---FindClass");
myjniclass = env->FindClass("com/example/file/jnitest01/Myjni");
if(myjniclass == NULL) {
return;
}
mid = env->GetMethodID(myjniclass,"MyToast","(Ljava/lang/String;)V");
if(mid == NULL) {
return;
}
//jstring 转 char* 需要开内存所以下面必须使用ReleaseStringUTFChars释放 防止泄露
pNativeStr = env->GetStringUTFChars(jStr, 0);
if(pNativeStr == NULL) {
return;
}
//重新生成一个jstring 也需要释放一下szOut
szOut = env->NewStringUTF(pNativeStr);
if(szOut == NULL) {
return;
}
//调用Myjni.MyToast 方法
env->CallVoidMethod(job, mid, szOut);
//释放pNativeStr char*指针
env->ReleaseStringUTFChars(jStr, pNativeStr);
//释放szOut
env->DeleteLocalRef(szOut);
}
JNIEXPORT void JNICALL Java_com_example_file_jnitest01_Myjni_NativeToast
(JNIEnv* env, jclass jc, jobject context, jstring jStr)
{
jclass tclass = NULL;
jmethodID mID = NULL;
jobject job = NULL;
jmethodID showId = NULL;
tclass = env->FindClass("android/widget/Toast");
if(tclass == NULL) {
return;
}
//获取makeText方法ID
mID = env->GetStaticMethodID(tclass,"makeText","(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;");
if(mID == NULL) {
return;
}
//调用makeText 第5个参数是makeText的duration
job = env->CallStaticObjectMethod(tclass, mID, context, jStr , 0);
if(job == NULL) {
return;
}
showId = env->GetMethodID(tclass,"show","()V");
if(showId == NULL) {
return;
}
env->CallVoidMethod(job, showId, context, jStr);
}
JNIEXPORT jstring JNICALL Java_com_example_file_jnitest01_Myjni_NativeString
(JNIEnv* env, jclass)
{
return env->NewStringUTF("NativeString");
}
5.创建Android.mk文件
代码如下:
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_CPP_EXTENSION := cpp LOCAL_MODULE := Myjni LOCAL_SRC_FILES := Myjni.cpp LOCAL_LDLIBS := -llog include $(BUILD_SHARED_LIBRARY)
6.创建Application.mk
代码如下:
APP_ABI := all APP_STL := stlport_static APP_OPIM := debug
7.修改Build.gradle 进行编译
Build.gradle:
ndk{ moduleName "myjni" //so文件名 }
externalNativeBuild { ndkBuild { path "src/main/jni/android.mk" } }
6.修改完成点击 Build->Build APK ,提示编译成功的话就可以添加调用Native方法的代码了
五、为Activity添加两个测试按钮
1.添加两个测试按钮
2.为按钮添加回调方法
3.在 MainActivity中实现回调方法并调用Native方法
代码:
public void button_MyjniToast(View view) { jni.MyjniToast("Myjni.MyjniToast->Myjni->MyToast"); } public void button_NativeToast(View view) { jni.NativeToast(this, "Myjni.NativeToast->android.widget.Toast"); }
六、Build APK 测试吧