Android studio NDK开发第二种方法 ndk-build:
- 首先环境配置必不可少,包括下载安装CMake,ndk-build插件,在上一篇“Android studio NDK成长记录(一)“中已经有详细介绍.
- 创建.c或者cpp源文件,和头文件,这一步可以先只是创建出.c和.h文件,不用急着书写.c源文件,只需搭好架子即可,书写c代码可以放到将gradle和ndk-build关联好之后,也就是第六步。(下面以c语言为例)
第一种方式:
在mian目录下新建jni文件夹。
选中Android Studio的左下角Terminal面板,输入命令“cd app/src/main/java”进入java目录,执行命令“javah 包名+类名“,这个命令是调用jdk中的javah.exe程序对native方法所在的Java类生成一个对应的.h头文件。这种方式生成的.h头文件中,自动将native方法在C语言中所对应的方法名全部生成出来了。然后将生成的.h文件剪切到cpp文件夹,并将.h文件中放方法名称copy到c文件中,将参数补全即可。
生成.h文件的命令如:“javah com.picovr.justndkbuild.nativeclass.JNI”
第二种方式:
在main目录新建文件夹jni,右键新建C/C++ Source File 勾选上Create an asscoiated hearder,这样就会生成一个.c文件和.h的头文件,这个.h文件不会像第一种方式那样自动生成native方法在C语言中所对应的方法名,需要自己手动去写。在学习阶段建议手动去做,更好地了解并熟悉jni的一些规则。 - 书写Android.mk文件,该文件名字必须为“Android.mk”,用于关联gradle和ndk-build,关联成功之后书写C代码时会有提示,否则不会有提示。Android.mk文件放在c资源文件所在module根目录中(比如app根目录)。书写好Android.mk文件后在module根目录下的build.gradle文件中配置ndk属性。Android.mk文件和build.gradle文件可配置如下:
build.gradle :android { compileSdkVersion 25 buildToolsVersion "25.0.0" defaultConfig { applicationId "com.picovr.justndkbuild" minSdkVersion 15 targetSdkVersion 25 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" ndk { ldLibs "log" moduleName "hello" } } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } }
Android.mk :LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) #生成的so库的名字,必须跟module(如app:)下的build.gradle中配置的moduleName名字相同 LOCAL_MODULE := hello LOCAL_LDFLAGS := -Wl,--build-id #需要在C代码中打印log到studio的控制台,第一步就需要配置该属性 LOCAL_LDLIBS += -llog #本地 source file的地址,必须配置,Java代码才能找到源文件,并关联起来,最后面的'\'是换行,有多个文件直接按下面形式列出即可 LOCAL_SRC_FILES := \ E:\AndroidStudioProjects\JustNDKBuild\app\src\main\jni\hello.c \ #本地 source file所在的目录 LOCAL_C_INCLUDES += E:\AndroidStudioProjects\JustNDKBuild\app\src\main\jni LOCAL_C_INCLUDES += E:\AndroidStudioProjects\JustNDKBuild\app\src\main\jni include $(BUILD_SHARED_LIBRARY)
- 将gradle和ndk-build关联起来 ,可以手动关联,也可以自动关联,最后的结果是一样的。<1.>自动关联 : 将工程改为Android视图,右键选中module(如app),选择Link C++ Project with Gradle,下拉选项中选择ndk-build,浏览找到你的项目中的Android.mk文件,点击确定即可,studio会自动在该module下的build.gradle文件中配置好externalNativeBuild属性,最终结果与手动关联是一样的。
<2.>手动关联 : 在module下的build.gradle中按照下方的模板配置externalNativeBuild属性,该属性是指向你的Android.mk文件,让gradle编译的时候能找到该文件,按照该文件的配置进行编译。
配置好之后的build.gradle应该如下模样,注意看externalNativeBuild属性:android { compileSdkVersion 25 buildToolsVersion "25.0.0" defaultConfig { applicationId "com.picovr.justndkbuild" minSdkVersion 15 targetSdkVersion 25 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" ndk { ldLibs "log" moduleName "hello" } } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } externalNativeBuild { ndkBuild { path 'Android.mk' } } }
- 书写java中的native方法,创建一个类,在该类中声明一个native方法,不需要实现。
package com.picovr.justndkbuild.nativeclass; /** * Created by PICO-USER Dragon on 2017/2/6. */ public class JNI { public native String getString(); }
- 书写c源代码
java中的native方法对应C语言中的方法的规则在下面的代码中已经详细解释:
copy下面的代码的时候,导包hello.h和jni.h分别copy,因为每个人的头文件名字不一样。ndk安装路径也不一样,所以jni.h所在目录不一样。/* Created by PICO-USER Dragon on 2017/1/17. 导包的时候要注意 1.你自己创建的.h文件必须要 2.jni.h必须要,这个导包的时候,studio应该会提示,其实就是你安装ndk所在目录下的platforms目录中的任意 一个版本中,可以在电脑中按照下面jni.h的那个路径中找来看看 */ #include "hello.h" #include "../../../../../../Android/SDK/ndk-bundle/platforms/android-21/arch-x86_64/usr/include/jni.h" #include <stdio.h> #include <stdlib.h> /** * 命名规则:返回值类型 + 方法名 * 方法名:是Java中native方法的包名+类名+方法名,并且把'.'给为'_' * * JNIEXPORT和JNICALL 可要可不要string Java_com_picovr_ndksupporttest_mynative_JNI_getString(JNIEnv *env, jobject jobj)也行 * * jstring 是返回值对应java中的String类 * JNIEnv *env 必须参数,在C中必须要用到这个参数去调用方法 * jobject jobj 必须参数 不一定用到 */ JNIEXPORT jstring JNICALL Java_com_picovr_ndksupporttest_mynative_JNI_getString(JNIEnv *env, jobject jobj) { //jstring (*NewStringUTF)(JNIEnv*, const char*);其实是在调用ndk-build中的jni.h中的方法 return (*env)->NewStringUTF(env, "The first jinDemo for Dragon !"); }
- 加载动态链接库,调用c代码
在native方法所在类中增加静态代码块,加载动态链接库package com.picovr.justndkbuild.nativeclass; /** * Created by PICO-USER Dragon on 2017/2/6. */ public class JNI { // Used to load the 'hello' library on application startup. static { //"hello"是so库的名字,也就是CMakeLists.txt文件中add_library()属性中的第一个参数 System.loadLibrary("hello"); } public native String getString(); }
- 调用native方法,看看是否成功!
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); String string = new JNI().getString(); Log.i("MainActivity", "onCreate string :" + string); } }