文件结构(选中的为生成的)
CMake构建不需要执行命令,会自动生成so文件打包进apk
Android mk构建需要执行命令生成so文件,再打包进apk。命令如下。
# 在jni目录下执行
# 生成com_demo_cppproject_OtherNdkTest.h头文件
javac -h ./ ../java/com/demo/cppproject/OtherNdkTest.java
# 构建出so文件
ndk-build NDK_PROJECTPATH=. NDK_APPLICATION_MK=Application.mk NDK_BUILD_SCRIPT=Android.mk NDK_LIBS_OUT=..\jniLibs\
MainActivity.java
package com.demo.cppproject;
public class MainActivity extends AppCompatActivity {
// Used to load the 'cppproject' library on application startup.
static {
System.loadLibrary("cppproject");
System.loadLibrary("DEMO");
}
private ActivityMainBinding binding;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityMainBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
TextView tv = binding.sampleText;
String temp = stringFromJNI() + "\n" + new MyNdkTest().getData() + "\n"
+ new OtherNdkTest().getName() + "==" + new OtherNdkTest().count();
tv.setText(temp);
}
public native String stringFromJNI();
}
MyNdkTest.java
package com.demo.cppproject;
public class MyNdkTest {
public native String getData();
}
OtherNdkTest.java
package com.demo.cppproject;
public class OtherNdkTest {
public native String getName();
public native int count();
}
CMakeLists.txt
# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html
# Sets the minimum version of CMake required to build the native library.
cmake_minimum_required(VERSION 3.22.1)
# Declares and names the project.
project("cppproject")
# 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.
cppproject
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
native-lib.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.
cppproject
# Links the target library to the log library
# included in the NDK.
${log-lib})
native-lib.cpp
#include <assert.h>
#include <jni.h>
#include <string>
#ifndef _Included_com_demo_cppproject_MyNdkTest
#define _Included_com_demo_cppproject_MyNdkTest
#ifdef __cplusplus
extern "C" {
#endif
JNIEXPORT jstring JNICALL Java_com_demo_cppproject_MainActivity_stringFromJNI(
JNIEnv *env,
jobject /* this */) {
std::string hello = "静态注册!cmake构建!Hello from C++";
return env->NewStringUTF(hello.c_str());
}
// 定义的对应java中的定义native方法, 采用动态注册
//extern "C" JNIEXPORT jstring JNICALL Java_com_demo_cppproject_MyNdkTest_getData(
JNIEXPORT jstring JNICALL getData(
JNIEnv *env,
jobject /* this */) {
std::string hello = "动态注册!cmake构建!get data";
return env->NewStringUTF(hello.c_str());
}
//需要动态注册的native方法所在的类
#define JNIREG_CLAS_MAIN "com/demo/cppproject/MyNdkTest"
//创建JNINativeMethod的数组,用来存放,JNINativeMethod结构变量,
// JNINativeMethod结构存放:注册的native方法,对应的签名,C++/C的对应的JNI方法
static JNINativeMethod gMethods[] = {
{"getData", "()Ljava/lang/String;", (void*)getData}
};
static int registerNativeMethods(JNIEnv *env, const char *className,
JNINativeMethod *gMethods, int numMethods) {
jclass clazz;
clazz = env->FindClass(className);
if (clazz == NULL) {
return JNI_FALSE;
}
if (env->RegisterNatives(clazz, gMethods, numMethods) < 0) {
return JNI_FALSE;
}
return JNI_TRUE;
}
/***
* 注册native方法
*/
static int registerNatives(JNIEnv *env) {
if (!registerNativeMethods(env, JNIREG_CLAS_MAIN, gMethods,
sizeof(gMethods) / sizeof(gMethods[0]))
) {
return JNI_FALSE;
}
return JNI_TRUE;
}
/**
* 如果要实现动态注册,这个方法一定要实现
* 动态注册工作在这里进行
*/
JNIEXPORT jint
JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
JNIEnv *env = NULL;
jint result = -1;
if (vm->GetEnv((void **) &env, JNI_VERSION_1_4) != JNI_OK) {
return -1;
}
assert(env != NULL);
if (!registerNatives(env)) { //注册
return -1;
}
result = JNI_VERSION_1_4;
return result;
}
#ifdef __cplusplus
}
#endif
#endif
demo.cpp
//
// Created by Admins on 2023/5/6.
//
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
#include <string>
/* Header for class com_demo_cppproject_MyNdkTest */
#ifndef _Included_com_demo_cppproject_OtherNdkTest
#define _Included_com_demo_cppproject_OtherNdkTest
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_demo_cppproject_MyNdkTest
* Method: getData
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_demo_cppproject_OtherNdkTest_getName
(JNIEnv *env, jobject){
std::string hello = "静态注册!Android mk构建!Hi from C++";
return env->NewStringUTF(hello.c_str());
}
/*
* Class: com_demo_cppproject_MyNdkTest
* Method: count
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_com_demo_cppproject_OtherNdkTest_count
(JNIEnv *env, jobject){
return 11;
}
#ifdef __cplusplus
}
#endif
#endif
Android.mk
# Android.mk 参数
# 设置工作目录,它用于在开发tree中查找源文件。宏my-dir由Build System提供,会返回Android.mk文件所在的目录
LOCAL_PATH := $(call my-dir)
# CLEAR_VARS变量由Build System提供。指向一个指定的GNU Makefile,由它负责清理LOCAL_xxx类型文件,
# 但不是清理LOCAL_PATH
# 所有的编译控制文件由同一个GNU Make解析和执行,其变量是全局的。所以清理后才能便面相互影响,这一操作必须有
include $(CLEAR_VARS)
# LOCAL_MODULE模块必须定义,以表示Android.mk中的每一个模块,名字必须唯一且不包含空格
# Build System 会自动添加适当的前缀和后缀。例如,demo,要生成动态库,则生成libdemo.so。
# 但请注意:如果模块名字被定义为libabd,则生成libabc.so。不再添加前缀。
LOCAL_MODULE := DEMO
# 指定参与模块编译的C/C++源文件名。不必列出头文件,build System 会自动帮我们找出依赖文件。
# 缺省的C++ 源码的扩展名为.cpp。
LOCAL_SRC_FILES := demo.cpp
# BUILD_SHARED_LIBRARY是Build System提供的一个变量,指向一个GUN Makefile Script。它负责收集自从上次调用include $(CLEAR_VARS)后的所有LOCAL_xxxxinx。并决定编译什么类型
# 1. BUILD_STATIC_LIBRARY:编译为静态库
# 2. BUILD_SHARED_LIBRARY:编译为动态库
# 3. BUILD_EXECUTABLE:编译为Native C 可执行程序
# 4. BUILD_PREBUILT:该模块已经预先编译
include $(BUILD_SHARED_LIBRARY)
# 命令:
# ndk-build NDK_PROJECTPATH=. NDK_APPLICATION_MK=Application.mk NDK_BUILD_SCRIPT=Android.mk NDK_LIBS_OUT=..\jniLibs\
Application.mk
#Application.mk 参数
APP_MODULES := DEMO
# 默认生成支持的多种类型.so
APP_ABI := all
APP_STL := c++_shared
#APP_PLATFORM := android-16不配置,打包.so会出错
APP_PLATFORM := android-19
参考:
JNI中native方法的几种注册方式
[NDK]-搭建ndk-build环境
Android Studio 4.0.+NDK .so库生成打包