又很久没写博文了,懒癌晚期,没得救了。
这次要分享的又是全干货,想往底层方向发展的筒靴避不开药学习JNI开发,今天就从搭建环境到完成第一个demo开始带大家入门(其实我也才刚开始学JNI开发,有不对之处欢迎大家指正)。
环境搭建
(1)下载NDK、CMake等
打开Android studio的设置,然后搜索SDK,选择Android SDK
选择上图中勾选的进行下载,然后应用
(2)配置环境变量
我这边是Mac系统,所以在.bash_profile文件内加入以下配置
export ANDROID_NDK_ROOT=/Users/你的/Library/Android/sdk/ndk/23.0.7599858
export PATH=$PATH:$ANDROID_NDK_ROOT
上面的路径就是第一步中下载NDK的路径,如果不配置这个环境变量,那你进行ndk编译时会遇到下面报错
ndk-build:command not found
注:如果不需要生成.so文件可以不配
至此,JNI开发环境搭建完成。
创建demo项目
(1)新建Native C++项目
这种方式创建会自动为你配置好CMake、native-lib库等;我们不采用这种方式,跟平时一样创建一个Empty Activity项目。完成之后,在main目录下心间jni文件夹,然后新建CMakeLists.txt
(2)配置CMakeLists.txt
cmake_minimum_required(VERSION 3.10.2)//最小CMake版本
# Declares and names the project.
project("jnidemo")
# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.
#定义需要编译的代码库
add_library( # Sets the name of the library.
native-lib //此处换成你新建的JNI库,有多个都在此添加
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
native-lib.cpp) //换成你的cpp文件
# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.
find_library( # Sets the name of the path variable.
log-lib
# Specifies the name of the NDK library that
# you want CMake to locate.
log )
# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.
#目标库
target_link_libraries( # Specifies the target library.
native-lib //此处换成你新建的JNi库,有多个都在此添加
# Links the target library to the log library
# included in the NDK.
${log-lib} )
然后在build.gradle下做如下配置:
android {
....
defaultConfig {
....
//配置CMake
externalNativeBuild {
cmake {
cppFlags ""
}
}
}
//配置CMake
externalNativeBuild {
cmake {
path "src/main/jni/CMakeLists.txt"
version "3.10.2"
}
}
}
(3)配置properties
gradle.properties
#gradle:3.0.1 studio3.0 之前用
android.useDeprecatedNdk=true
#gradle:3.0.1 studio3.0 之后用
android.deprecatedNdkCompileLease=1511832698813
local.properties
sdk.dir=/Users/你的/Library/Android/sdk
ndk.dir=/Users/你的/Library/Android/sdk/ndk
(4) 新建要编译成.h文件的java文件
public class JNIUtils {
static {
System.loadLibrary("JNIDemo");
}
public static native String stringFromJNI();
}
然后在Terminal控制台进入main目录下执行javah -d ./jni/ -classpath ./java/ -jni com.example.jnidemo.JNIUtils命令,就会在jni目录下生成JNIUtils.java的.h 头文件
(5)在jni目录下新建.c或者.cpp文件
#include <jni.h>
#include <string>
#include "com_example_jnidemo_JNIUtils.h"
extern "C" JNIEXPORT jstring JNICALL
Java_com_example_jnidemo_JNIUtils_stringFromJNI
(JNIEnv* env,
jclass) {
std::string hello = "Hello from C++";
return env->NewStringUTF(hello.c_str());
}
(6)在你想要调用的地方直接使用JNI接口
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView tv = findViewById(R.id.sample_text);
tv.setText(JNIUtils.stringFromJNI());
}
}
至此,你就可以编译安装看一下效果了,不过在编译安装之前你需注释掉gradle.properties和local .properties有关ndk的配置,不然会报错的哟!!!!
生成.so文件
这样就完事了吗?
没有,如果其他地方需要使用,还得打包成.so文件,如何生成?在这一步的时候走了不少弯路,碰到了ndk-build命令无效,甚至不知道执行什么命令来生成.so。在网上找了不少博客,在上面的操作之后,还需要在jni目录下心间Android.mk和Application.mk文件方可生成.so.
(1) Android.mk
LOCAL_PATH := $(call my-dir) //jni目录
include $(CLEAR_VARS)
LOCAL_MODULE := JNIDemo //库名
LOCAL_SRC_FILES := JNIUtils.cpp //需要编译的文件
include $(BUILD_SHARED_LIBRARY)
(2) Application.mk
APP_ABI := all //指定so文件的平台 ,设置为all, 代表所有平台
APP_PLATFORM := android-16
APP_STL := c++_shared //去掉会报错
至此,就可以愉快的执行ndk-build命令了(同样在main目录下执行) 。