基于Android Studio3.5
user:纯粹.so连接库使用者
creator:纯粹ndk开发者,创建.so
designer:在现有的.so进行开发.so连接库特定功能
纯粹.so连接库使用者
在main下新建jniLibs,是默认的.so放置。创建者提供JNI接口,JNI是根据包名找到C/C++函数,使用时候必须和creator定义的接口完全一致(包括包名)
-jniLibs
-arm64-v8a
xx.so
-armeabi-v7a
xx.so
....
JNI接口实现有两种java或者kotlin如下
package cn.george.nativecreator;// 包名一定要和so中提供的一致
/**
* Created By George
* Description: java实现JNI
*/
public class MainActivity {
static {
// 注意不是libnative-lib.so
System.loadLibrary("native-lib");
}
public static native String stringFromJNI(String top, String bottom, String brow, String eyes);
}
package cn.george.nativecreator// 包名一定要和so中提供的一致
/**
* Created By George
* Description:kotlin实现JNI
*/
class MainActivity {
companion object{
init {
System.loadLibrary("native-lib")
}
}
external fun stringFromJNI( top:String, bottom:String ,brow: String , eyes:String ):String
}
注意:
如果只用一个.so库,比如:项目中之支持armeabi-v7a,则需要在app的build中添加:
android{
defaultConfig{
...
ndk {
abiFilters 'armeabi-v7a'
}
}
}
....
}
纯粹ndk开发者,创建.so
在Android Studio中需要创建一个Native C++的Android项目,会自动生成
-main
-cpp
CmakeLists.txt
xxx.cpp
CmakeLists用来配置加入的.h .cpp文件,全局变量等
MainActivity中会自动生成JNI的native接口方法和C++实现
arm 架构注重的是续航能力:大部分的移动设备
x86 注重性能:大部分台式机和笔记本电脑
可以在build中控制.so输出种类
android {
defaultConfig {
externalNativeBuild {
cmake {
abiFilters 'armeabi-v7a', 'arm64-v8a'
}
}
}
.so默认是生成在app/build/intermediates/cmake下分为debug和release
在build中也可以自定义.so的输出位置
android {
...
sourceSets {
main {
jniLibs.srcDirs = ['target']//指定so库的位置,加载so库
}
}
}
arm64-v8a: 第8代、64位ARM处理器
armeabi-v7a :第7代及以上的 ARM处理器
x86: x86架构的CPU(Intel CPU)
x86_64: x86架构的64位CPU(Intel的CPU)
.so .dll .dylib都是由C++实现的。
.so用在linux上,.dll用在windows上,.dylib用在MacOS中。
他们都是C++的动态链接库(Dynamic Link Library)
注意:
如果在写C/C++代码确认自己写的没问题,但是飘红Build-->Refresh Linked C++ Projects
通过Build-->Make Project生成.so
在现有的.so进行开发.so连接库特定功能
比如FFmpeg和OpenCV都是这种实现。
同样你需要创建Native C++项目作为第三方源码库,可以添加一些基本操作,比如加,减,乘,除
extern "C" int add(int a, int b) {
return a + b;
}
然后生成three-lib.so库作为第三方库。
同样要创建Native C++项目作为自定义第三方库的项目。
把第三方库three-lib.so放到这个项目的jniLibs/支持的cpu架构/下
然后对CMakeLists.txt处理
cmake_minimum_required(VERSION 3.4.1)
# 第三方so的名字注意不是libthree-lib,动态库标志,导入第三方标志
add_library(three-lib SHARED IMPORTED)
# 这两个属性必须靠在一起,下边是对上边的解释;第三方so名字,设置so的路径armeabi-v7a等
set_target_properties(three-lib PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/../jniLibs/${ANDROID_ABI}/libthree-lib.so)
# 自定义jni的名字,动态库标示,jni源文件
add_library(native-lib SHARED native-lib.cpp)
# 配置include路径(如果需要使用.h文件的话),这里没有用到,可以去掉
target_include_directories(native-lib PRIVATE ${CMAKE_SOURCE_DIR}/../myinclude)
find_library(log-lib log)
# 链接所有的.cpp .so,(.h文件不需要),第三方so的名称
target_link_libraries(native-lib three-lib ${log-lib})
在自定义native-lib.cpp中进行代码调用第三方库
extern "C" JNIEXPORT int JNICALL
Java_cn_george_nativedesigner_MainActivity_add(
JNIEnv *env,
jobject /* this */,jint a,jint b) {
LOGD("加法");
return add(a,b);
}
在MainActivity添加add方法(kotlin)
external fun divi(a:Int,b:Int):Int
companion object {
// Used to load the 'native-lib' library on application startup.
init {
System.loadLibrary("native-lib")
}
}
然后可以调用java的jni add进行加法运算。
注意:
如果想在native打印日志需要在build中引入日志库
android{
...
defaultConfig{
...
ndk{
moduleName "Iso8583Lib"// 日志相关编码
ldLibs "log", "z", "m"// 日志相关
abiFilters 'armeabi-v7a'// 只引用指定特定cpu架构
}
externalNativeBuild {
cmake {
cppFlags ""
abiFilters 'armeabi-v7a'// 产出指定的cpu架构
}
}
}
}
注意:
在混合编码c、ndk、java、jni时候需要注意变量类型的转化
Java_cn_george_nativedesigner_MainActivity_stringFromJNI(
JNIEnv *env,
jobject /* this */) {
std::string hello = "Hello from C++";
return env->NewStringUTF(hello.c_str());
}
所有的本地方法的第一个参数都是指向JNIEnv结构的。这个结构是用来调用JNI函数的。第二个参数jobject的意义,要看方法是不是静态的(static)或者(Instance)的。前者代表一个类对象的引用,后者被调用的方法所属对象的引用。返回值和参数类型根据等价约定映射本地C/C++类型,如下JNI类型映射表
JNI类型映射表
网友评论