总结一下:

android调用 android 调用JNI 分为静态调用与动态调用(不论动态还是静态前提都是NDK环境已经配置好的前提下)

一、静态主要就是将c(.c)或者c++(cpp)的源文件直接加到项目中进行调用,

android 调用JNI SO动态库_ar

然后在CMakeLists.txt中进行配置。

 二、动态调用

1、动态调用使用已经编译好的动态库.so文件

android 调用JNI SO动态库_ar_02

 2、android调用ndk类

android 调用JNI SO动态库_so文件_03生成后的so文件



public class SerialPort {

p
*/
public static native int GetSOVer(String ar);



static {
System.loadLibrary("serialport");//初始化so库(注意这里添加是需要去掉lib与.so)

}
}

3、.c文件添加

/*
* Copyright 2009-2011 Cedric Priscal
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <jni.h>
#include <termios.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include "M1900_drv.h"
#include "SerialPort.h"
#include "include/tinyalsa/audio_i2s.h"
#include "include/tinyalsa/asoundlib.h"
#include "android/log.h"
#include "newland_linux_so.h"

static const char *TAG = "serial_port";
#define LOGI(fmt, args...) __android_log_print(ANDROID_LOG_INFO, TAG, fmt, ##args)
#define LOGD(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, TAG, fmt, ##args)
#define LOGE(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, TAG, fmt, ##args)



//测试 Java_(固定)_com_littt_util_SerialPort(android包名原来的.更改为_,string ar 传入的字符串参数,JNIEnv *env, jclass固定写法)
JNIEXPORT jint JNICALL
Java_com_littt_util_SerialPort_GetSOVer(JNIEnv *env, jclass clazz, jstring ar) {
// TODO: implement GetSOVer()
return 9;//返回一个9的值
}

4、.h头文件中声明

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class android_serialport_api_SerialPort */

#ifndef _Included_android_serialport_api_SerialPort
#define _Included_android_serialport_api_SerialPort
#ifdef __cplusplus
extern "C" {
#endif


JNIEXPORT jint JNICALL
Java_com_littt_util_SerialPort_GetSOVer(JNIEnv *env, jclass clazz,jstring v);



#ifdef __cplusplus
}
#endif
#endif

 5、头文件与c文件写好了,就需要在CMake 中添加.c与.h都需要添加

# 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.4.1)

# 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.
serialport

# Sets the library as a shared library.
SHARED

# Provides a relative path to your source file(s).
M1900_drv.c
M1900_drv.h
audio_i2s.c
linux_so.cpp
mixer.c

include/tinyalsa/asoundlib.h
include/tinyalsa/audio_i2s.h
)

# 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.
serialport

# Links the target library to the log library
# included in the NDK.
${log-lib})

set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -s")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -s")

6、在build.gradle同样需要配置

plugins {
id 'com.android.application'
}

android {
compileSdkVersion 28
buildToolsVersion "28.0.3"

defaultConfig {
applicationId "com.littt.interphone"
minSdkVersion 17
targetSdkVersion 28
versionCode 1
versionName "1.0"

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
// cmake
externalNativeBuild {
cmake {
cppFlags ""
abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
}
}

}
externalNativeBuild {
cmake {
path "src/main/cpp/CMakeLists.txt"
version "3.10.2"

}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
sourceSets {
main {
jniLibs.srcDirs = ['libs']
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}

ndkVersion '22.1.7171670'
}

dependencies {

// implementation 'androidx.appcompat:appcompat:1.2.0'
// implementation 'com.google.android.material:material:1.2.1'

}

7、如果静态调用可以成功,那么就可以生成动态so库文件

android 调用JNI SO动态库_ar_04 

点击图中锤子会进行编译。完成后可以打开如下路径查看 

android 调用JNI SO动态库_so文件_05

红框中生成后 so文件

7.1、生成的.so文件(工程文件夹模式)目录为app/build/intermediates/ndk/lib,将其复制到另一个工程的app/lib目录下。

7.2、要使用上述的.so文件 ,必须将工程的包名改为生成.so文件时的包名,要不然 编译能通过,但是app不能正常运行。logcat会提示找不到所调用函数的实现。

7.3、将so文件复制到需要的路径下。

7.4、在gradle.properties中最后加一行:android.useDeprecatedNdk=true。

                                                                   -END