NDK使用

作者: 主音King | 来源:发表于2019-11-14 13:01 被阅读0次

基于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类型映射表

相关文章

网友评论

      本文标题:NDK使用

      本文链接:https://www.haomeiwen.com/subject/crqhictx.html