C++开发支持Android共享库(so)教程

C/C++动态加载So编程 dladdr、dlclose、dlerror、dlopen、dlsym等动态链接加载器的编程接口和示例。 阅读详情

C++开发支持Android共享库(so)教程

概述:

Android是运行于Linux上的移动系统,Android开发语言是java,Linux开发语言是C/C++。虽然google和java为Android提供了大部份功能库和SDK,但在一些情况下还是需要使用C++开发一些功能供Android调用,扩充Android功能。比如我们需要开发特有的功能库,但这样的库java没有提供;比如我们需要调用Linux系统的API,但java没有提供这样的调用接口等。

通过JNI(Java Native Interfac,中文为JAVA本地调用,通过这个接口可以实现C++,java相互调用)的支持可以开发出支持java调用的C++共享库(so),通过Android的NDK编译,可以生成支持Android调用的so库。

开发支持Android调用的so库大概需要经过下列三大步:

1) 用C/C++开发出Linux的so库,如果已经熟悉可跳过阅读。

2) 在C/C++代码里加入JNI,支持java通过JNI调用so库,如果已经熟悉可跳过阅读。

3) 通过android的NDK编译,生成支持Android调用的so库。

下面我们通过这三步实现Android调用C/C++开发so库

4) 补充主题

用C/C++开发出Linux的so库。

开发分析:

一个so需要提供允许外面调用的接口和so内部调用外部的调口,因些我们的so库需要向外部提供三个接口:1注册一个外部接口到so,so运行过程中调用;2..外部调用so功能的接口。现在我们把第一个接口定义成外部通过个接口注册一个接口个so内部,第二个接口设计通过外部调用,so内部开始调用第一个接口注册外部函数。

  逻辑分析:1.定义一个全局的函数指针,第一个接口注册函数把外部函数指针保到这个变量里;2.第二个启动函数开启一个线程,这个线程定时调用全局函数指针。

开发准备:

      1、ubuntu14-server,搭建好C/C++开发环境,搭建过程不在本教程讨论范围,搭建过程可参考其它文档。

      2、C++ 代码编辑IDE,一个普通的文件编辑器或专业的C++IDE都可。

编写so库的代码如下

新建一个C++文件jni_demo1.cpp 在文件输入下列代码

//本文件演示Android通过JNI调用C++开发so过程

#include <iostream>

#include <pthread.h>     //线程库

#include <unistd.h>  //usleep函数

 

using namespace std;

typedef void (*pExternalFunction)(unsigned int iParam); 

pExternalFunction g_pExternalFunction = NULL;   //实现函数指针,保存外部注册的函数

 

//外部向so注册一个函数供so内部调用

extern "C" void RegisterExternalFunction(pExternalFunction pExFun)

{

    g_pExternalFunction = pExFun;    //把回调函数保存起来

}

 

//线程启动后,定时调用外部注册的函数

void* start_routine(void *pParam)

{

    if(NULL == g_pExternalFunction){

        cout<<"start_routine pParam is NULL"<<endl;

        return (void*)0;

    }

    unsigned int iParam = (unsigned int)pParam;

    for(int i=0; i<2; i++){

        g_pExternalFunction(iParam); //调用外部函数,并把参数传入

        usleep(10000);

    }

    return (void*)0;

}

 

//创建一个线程,通过线程定时调用外部注册的回调数

extern "C" bool Start(unsigned int iParam)

{

    pthread_t thread = 0;

    pthread_attr_t attr;

    void *status = NULL;

    if(0 != pthread_create(&thread, NULL,start_routine, (void*)iParam)){

        cout<<"pthread_create no"<<endl;

        return false;

    }

    int iResult = pthread_join(thread, &status);     //等待线程结束返回

    return true;

}

 

编写makefile把上述代码编译成so库

1) 在jni_demo1.cpp同目录下新建一个文件makefile,这个主文件没有扩展名,输入下面代码。

jni_demo1.so:jni_demo1.o

g++ -shared -fpic -o jni_demo1.so jni_demo1.o -pthread

jni_demo1.o:jni_demo1.cpp

g++ -c jni_demo1.cpp

 

.PHONY:clean

clean:

rm -rf *.o

rm -rf *.so

 

2)将这两个文件放到Linux某个目录上,jni_demo1.cpp和makefile在同一目录,进入存放这两个文件的目录,执行make编译,输出如下信息,产生一个so共享库。

 

jni_demo1.so就是我们的目录文件so共享库文件

3) 编写一个测试文件,测试so文件是否正常工作。在同级目录下新建一个tmain1.cpp文件,输入下面代码

//演示怎样调用so接口

#include <iostream>

#include <dlfcn.h>

#include <unistd.h>  //usleep函数

using namespace std;

 

typedef void (*pExternalFunction)(unsigned int iParam); 

//定义so的函数原型

typedef void (*pRegisterExternalFunction)(pExternalFunction pExFun);

typedef bool (*pStart)(unsigned int iParam);

 

//注册到so内部,高so从内部调用的函数

void ExternalFunction(unsigned int iParam)

{

    cout<<"ExternalFunction out iParam="<<iParam<<endl;

}

 

int main(int argc, char *argv[])

{

    void *handle = NULL;

    pRegisterExternalFunction RegisterExternalFunction = NULL;

    pStart Start = NULL;

 

    //加载so库,相当于Win32的LoadLibrary

    handle = dlopen("/home/pengac/jni/jni_demo1.so", RTLD_LAZY);    ///home/pengac/jni/jni_demo1.so 共享库存放的绝对地址,根据实现环境设置

    if(NULL == handle){

        cout<<"dlopen jni_demo1.so failed"<<endl;

cout<<dlerror()<<endl;

        return 0;

    }

 

    //获取so库里的函数

    RegisterExternalFunction = (pRegisterExternalFunction)dlsym(handle,"RegisterExternalFunction");

    if(NULL == RegisterExternalFunction){

        cout<<"dlsym get RegisterExternalFunction failed"<<endl;

        cout<<dlerror()<<endl;

        goto out;

    }

    Start = (pStart)dlsym(handle,"Start");

    if(NULL == Start){

        cout<<"dlsym get Start failed"<<endl;

        cout<<dlerror()<<endl;

        goto out;

    }

    

    //调用函数so提供的接口

    RegisterExternalFunction(ExternalFunction);     //注册外部函数到so

    if(true == Start(55)){

        cout<<"Start return true"<<endl;

    }

    else

    {

        cout<<"Start return failed"<<endl;

    }

 

    out:

    //释放so库,相当于Win32的FreeLibrary

    if(0 != dlclose(handle))

    {

        cout<<"dlclose jni_demo1.so failed"<<endl;

cout<<dlerror()<<endl;                     //输出失败原因

        return 0;

    }

 

    return 0;

}

 

在控制台上执行 g++ tmain1.cpp -ldl 编译,产生可执行文件a.out,总共文件如下图所示

 

执行./a.out测试so是否正常,输入如下图结果表示so工作正常。

 

 

结论:

通过上述步骤已经实现了一个可以正常工作的so库,本so库共暴露出两个接口RegisterExternalFunction和Start。RegisterExternalFunction注册一个部外部方法到so内部,Start在so内部启动一个线程,实现从so内部调用外部方法的示例。通过上述演示,我们清楚地看到了外部怎样调用so方法和so怎么调用外部方法的过程,接下来我们通过往上述so加入JNI支持,实现java调用so方法和so调用java方法示例

 

在C/C++代码里加入JNI,支持java通过JNI调用so库

前述

1、JNI 是Java Native Interface的缩写,中文译为“Java本地调用”。通常使用JNI技术可以做到以下两点:

(1)Java程序中的函数可以调用Native语言函数,Native函数一般指的是C/C ++编写的函数;

(2)Native程序中的函数可以调用Java层的函数,也就是说在C/C++程序中可以调用Java层函数。

2、当然任何事物都有两面性,JNI也不例外,使用JNI主要缺点有以下两点:

(1)使用JNI技术将导致Java Application不能跨平台。如果要移植到别的平台上,那么Native代码就要重新进行编写;

(2)Java是强类型的语言,而C/C++不是,因此在编写JNI的时候要非常谨慎。

 

3、Android主要使用java开发,但Android可以通过java的JNI调用C/C++编写的so库,实现Android对C/C++的支持。接下来我们在前面so的基础上加入JNI,以支持java通过JNI调用so的方法。

Java部分

1、搭建java环境、

  (1)在控制台输入java,如果电脑上还没有安装,则显示下面信息,让我们选择一个安装

 

(2)我选择的是default-jre,在控制台`输入sudo apt-get install default-jre,等待一段时间后显示下面,表示安装结束。

 

(3)执行命令java -version,显示下面所示信息表示安装成功

 

(4)我们需要javah把java声明的接口生成C++对应的接口,输入javah,如果出下图信息,表示还没安装。

 

我选择安装openjdk-7-jdk,执行命令 sudo apt-get install openjdk-7-jdk 安装。如果安装过程没有出错,将出现下图所示。

 

输入javah -version出现下图所示信息,表示安装成功

 

 

2、编写java与C++对应的接口代码,在C++文件同级目录下新建一个tjni.java文件,输入下面代码

//本文件演示如何通过JNI实现java与C++互相调用

import java.util.*;

 

//定义供so调用的java外部函函数

class ExternalFunction

{

    public void externalFunction(int iParam)

    {

        System.out.println("This is so invoke java function iParam=" + iParam);

    }

}

 

public class tjni

{

    //声明与so对应的两个函数,native关键字表示

    public native void RegisterExternalFunction(ExternalFunction func);

    public native boolean Start(int iParam);

    

    static{

        System.loadLibrary("jni_demo2");   //在win32下,加载jni_demo2.dll 在Linux下加载libjni_demo2.so,注意:库文件必须放在任何java.library.path包含的路径中,可用 System.getProperties().list(System.out);打印出来

    }

    

    public static void main(String[] args)

    {

        tjni obj = new tjni();

ExternalFunction Efun = new ExternalFunction();

obj.RegisterExternalFunction(Efun); //注册外部的函数到so

if(true == obj.Start(55)) //调用so的接口函数

        {

            System.out.println("Start return true");

        }

        else

        {

            System.out.println("Start return false");

        }

    }

}

 

3、编译tjni.java文件。

   执行javac tjni.java 命令,如果没有输出任何信息,表示编译成功,这时将产生两个 .class文件:tjni.class;ExternalFunction.class

 

4、生成对应的C++头文件

a) 执行 javah tjni 命令,如果没误发生,将产生tjni.h文件,文件里声明了两个函数,与tjni.java 的两个navtive函数对应,分别是:

JNIEXPORT void JNICALL Java_tjni_RegisterExternalFunction

  (JNIEnv *, jobject, jobject) 与 public native void RegisterExternalFunction(ExternalFunction func) 对应。

JNIEXPORT jboolean JNICALL Java_tjni_Start

  (JNIEnv *, jobject, jint) 与 public native boolean Start(int iParam) 对应。

 

5、在原来的so的C++代码基础上,加入JNI支持so与java互相调用。

a) 把原来的 jni_demo1.cpp 改成 jni_demo2.cpp,并把代码修改成如下代码

//本文件演示Android通过JNI调用C++开发so过程

#include <iostream>

#include <pthread.h>     //线程库

#include <unistd.h>  //usleep函数

#include "tjni.h"            //java生成的对应C++头文件

 

using namespace std;

typedef void (*pExternalFunction)(unsigned int iParam);

pExternalFunction g_pExternalFunction = NULL; //实现函数指针,保存外部注册的函数

 

//定义全局对象,用于so通过JNI调用外部java函数

 

typedef struct _tagJNIAdapter {

    jobject objInterface;

    jobject objCallBack;

    JavaVM* pVm;

 

    _tagJNIAdapter() {

        pVm = NULL;

    }

} JNIADA;

JNIADA g_jniAda;

 

//外部向so注册一个函数供so内部调用

 

//extern "C" void RegisterExternalFunction(pExternalFunction pExFun) {

//    g_pExternalFunction = pExFun; //把回调函数保存起来

//}

 

//线程启动后,定时调用外部注册的函数

 

void* start_routine(void *pParam) 

{   

    if (NULL != g_jniAda.pVm) {

        unsigned int iParam = (unsigned int)pParam;

        JNIEnv *pEnv = NULL;

        g_jniAda.pVm->AttachCurrentThread((void**) &pEnv, NULL); //与当前线程关联

        jclass jcls = pEnv->GetObjectClass(g_jniAda.objInterface);

 

        if (jcls == NULL) {

            g_jniAda.pVm->DetachCurrentThread();

            return (void*) 0;

        }

 

        jmethodID jmetFunc = pEnv->GetMethodID(jcls, "externalFunction", "(I)V");    //获取外java函数数

        if (NULL == jmetFunc) {

            g_jniAda.pVm->DetachCurrentThread();

            return (void*)0;

        }

 

        for (int i = 0; i < 2; i++) {

            pEnv->CallIntMethod(g_jniAda.objInterface, jmetFunc, iParam);    //通过java 虚拟机调用java外部java函数

        }

        g_jniAda.pVm->DetachCurrentThread();

 

    }

 

    return (void*) 0;

}

 

//创建一个线程,通过线程定时调用外部注册的回调数

extern "C" bool Start(unsigned int iParam) {

    pthread_t thread = 0;

    pthread_attr_t attr;

    void *status = NULL;

    if (0 != pthread_create(&thread, NULL, start_routine, (void*) iParam)) {

        cout << "pthread_create no" << endl;

        return false;

    }

    int iResult = pthread_join(thread, &status); //等待线程结束返回

    return true;

}

 

//实现java实现的头文件

 

void JNICALL Java_tjni_RegisterExternalFunction

(JNIEnv *pEnv, jobject obj1, jobject obj2) {

    cout << "this is Java_tjni_RegisterExternalFunction" << endl;

 

    //把java外部实现的方法实现保存起来,

    pEnv->GetJavaVM(&g_jniAda.pVm);

    g_jniAda.objCallBack = pEnv->NewGlobalRef(obj1);

    g_jniAda.objInterface = pEnv->NewGlobalRef(obj2);

}

 

jboolean JNICALL Java_tjni_Start

(JNIEnv *, jobject, jint iParam) {

    cout << "this is Java_tjni_Start" << endl;

    return Start(iParam);

}

 

b)代码解释:

C++代码包含了头文件#include "tjni.h", 这个头文件由刚刚的javah tjni生成,而tjni.h 里又包含了 #include <jni.h> 头文件,这个头文件是由java安装时自还的,在java 的安装目录下,修改的时间需要链接上这个头文件。

c)关键代码说明:

 jmethodID jmetFunc = pEnv->GetMethodID(jcls, "externalFunction", "(I)V"); 

这句C++代码通过虚拟机调用java外部的函函数,externalFunction是tjni.java文件里定义的public void externalFunction(int iParam)函数。(I)V表示这个函数的类型,可以通过javap来获取函数的定义信息,本教程中,externalFunction函数是定义在ExternalFunction在类中,所以执行 javap -s -p ExternalFunction 获取得到下面信息。

 

 

 

6、修改makefile文件

a) makefile修改如下

libjni_demo2.so:jni_demo2.o

g++ -shared -fpic -o libjni_demo2.so jni_demo2.o -pthread

jni_demo2.o:jni_demo2.cpp

g++ -c jni_demo2.cpp -I /usr/lib/jvm/java-7-openjdk-i386/include -I /usr/lib/jvm/java-7-openjdk-i386/include/linux

 

.PHONY:clean

clean:

rm -rf *.o

rm -rf *.so

代码解释: 原因翻译时需要加入jni.h头文件的支持,需要加入-I /usr/lib/jvm/java-7-openjdk-i386/include让make编译时可以找到jni.h文件。

 

7、编译新的so库

a) 执行 make命令重新编译so库,出现下面信息表示编译成功,生成新的so库libjni_demo2.so

 

 

8、执行java tjni测试java与so的调用。

a)这里如果执行 java tjni,将出现下图所示错误,原因是在 java.library.path目录下找不到libjni_demo2.so文件,在tjni.java中的代码System.loadLibrary("jni_demo2"); 将到java.library.path目录下加载libjni_demo2.so共享库文件。

 

b)解决办法是将libjni_demo2.so拷贝到java.library.path指向的目录,通过System.getProperties().list(System.out); 代码可以查看java.library.path指向的目录,我的测试环境指向 /usr/lib ,执行 cp libjni_demo2.so /usr/lib命令把so库复到目录。

c)执行java tjni输出如下图所示,表示java与so库互调成功

 

 

 

this is Java_tjni_RegisterExternalFunction

this is Java_tjni_Start

上面这两句是java调用C++,C++打印的信息

 

This is so invoke java function iParam=55

This is so invoke java function iParam=55

上面这两句是C++回调java,java打印的信息

 

结论:

通过上述过程,演示了java与C++ so的相互调用,Win32的调用方式也一样。本节的关键点是。

a) java方面

 Java 要与C++ 交互的函数要用 native 声明,表明这个函数将与C++交互,将由C++实现native声明的函数,如本教程的public native void RegisterExternalFunction(ExternalFunction func);与public native boolean Start(int iParam);两个函数。

编译通过后,用javah来生成C++头文件,每一个native都会生成一个C++的函数对应,比如 public native boolean Start(int iParam) 和JNIEXPORT jboolean JNICALL Java_tjni_Start(JNIEnv *, jobject, jint)对应。

b)C++部分

C++通过实现native对应的函数实现java的调用功能,如本教程JNIEXPORT jboolean JNICALL Java_tjni_Start(JNIEnv *, jobject, jint)实现了java函数的调用。

c)C++的so和java如何关联。

通过java代码

static{

System.loadLibrary("jni_demo2");

}

在win32下,加载jni_demo2.dll 在Linux下加载libjni_demo2.so,注意:库文件必须放在任何java.library.path包含的路径中,可用 System.getProperties().list(System.out);打印出来

至于so调用java部分,参考本教程代码。

 

三、通过android的NDK编译,生成支持Android调用的so库

前述

一、虽然android java也是通过JNI调用so库,但与Linux的JNI还有些不同:

a) Linux使用makefile编译,android使用NDK编译,NDK是在makefile的基础上包装了一层,以适应android调用。

b) 代码有细微不同,在代码示例中碰到会讲

二、本节还会讲到怎样在C++代码中加入调试日志信息,在android开发中通过C++输出的代码定位日志。

c) 更多的NDK介绍参考:http://emuch.net/html/201207/4690329.html

 

准备工作

一、下载NDK

我下载的是win32版本

下载地址:http://dl.google.com/android/ndk/android-ndk-r9-windows-x86.zip

二、搭建并验证NDK环境是否正常。

a) 将下载的文件android-ndk-r9-windows-x86.zip解压到任何目录,本教程解压到E盘根目录。

b)按顺序执行:开始->运行->cmd,进入控制台窗口,进入E:\android-ndk-r9\samples\hello-jni目录,如下图所示:

 

c) 执行ndk-build命令,将编译NDK自带的demo,如下图所示表示编译环境正常。

 

 

 

使用NDK把C++代码编译成可支持android的so

一、为了其前面两步的区分,把jni_demo2.cpp改成jni_demo3.cpp,进入刚刚测试NDK的目录:E:\android-ndk-r9\samples\hello-jni。目录结果如下图所示。

 

把我们的C++源文件放jni目录下,并修改Android.mk文件,就可以编译了,原始jni目录如下图所示。Android.mk是makefile文件;hello-jni.c文件是原始的demo文件。

 

a)我们把自己的jni_demo3.cpp和tjni.h拷贝到这个目录,拷贝后的E:\android-ndk-r9\samples\hello-jni\jni目录如下图所示。

 

b)修改Android.mk文件。把原来的

LOCAL_MODULE    := hello-jni

LOCAL_SRC_FILES := hello-jni.c

改成

LOCAL_MODULE    := jni_demo3

LOCAL_SRC_FILES := jni_demo3.cpp

修改后的内容如下

LOCAL_PATH := $(call my-dir)

 

include $(CLEAR_VARS)

 

#LOCAL_MODULE    := hello-jni

#LOCAL_SRC_FILES := hello-jni.c

 

LOCAL_MODULE    := jni_demo3#编译后的so文件名

LOCAL_SRC_FILES := jni_demo3.cpp  #C++源文件列表。

 

include $(BUILD_SHARED_LIBRARY)

 

c) 先执行ndk-build clean清楚工程,再执行ndk-build,编译时出现如下图所示错误,这个错误在Linux 的JNI下是没有出现的,这是NDK与makefile代码差别引起,接下来我们对这个错误进行修改。

 

 

二、在C++代码加入开关宏。

为解决上面翻译错误,我们在代码里加入一个开宏,用于区分是在普通makefile下编译还是在NDK下编译,通过本小节,知道怎么在NDK编译时传入开关宏。

a) 通过代码分析,定位出是g_jniAda.pVm->AttachCurrentThread((void**) &pEnv, NULL);编译不通过,在NDK这句代码应该改成g_jniAda.pVm->AttachCurrentThread((void**) &pEnv, NULL);。在代码里加入开关宏,在NDK编译时编译NDK的代码,修改后的代码如下。

#ifdef NDK

g_jniAda.pVm->AttachCurrentThread(&pEnv, NULL); // android平台

#else

        g_jniAda.pVm->AttachCurrentThread((void**) &pEnv, NULL); 

#endif

 

b) 并修改 Android.mk文件,加入LOCAL_CPPFLAGS += -D NDK,支持编译时加入开关宏。修改后的文件内容如下,注意:必须加在include $(CLEAR_VARS)后面,否则无效

LOCAL_PATH := $(call my-dir)

 

include $(CLEAR_VARS)

 

LOCAL_CPPFLAGS += -D NDK

 

#LOCAL_MODULE    := hello-jni

#LOCAL_SRC_FILES := hello-jni.c

 

LOCAL_MODULE    := jni_demo3

LOCAL_SRC_FILES := jni_demo3.cpp

 

include $(BUILD_SHARED_LIBRARY)

 

c) 再执行ndk-build命令,编译通过

 

 

编译通过后,目标文件在E:\android-ndk-r9\samples\hello-jni\libs目录下,armeabi目录下的是arm平台的so

d) 再加入一个文件Application.mk到E:\android-ndk-r9\samples\hello-jni\jni,添加后目录结构如下图所示。

 

文件内部是:

APP_ABI := all

APP_STL := stlport_static

 

再重新编译,将生成更多硬件平台的so,生成后的目录如下图所示。

 

 

到些,已经把C++怎么写出一个支持andorid运行的so过程讲解完成。下面是一些C++开发andorid一些补充。

其它主题

加入日志输出:

1、包含头文件  #include <android/log.h>

2、打印日志函数  __android_log_print(ANDROID_LOG_DEBUG, "title", "content:%s Line:%d\n", __FILE__, __LINE__);

3、并在Android.mk加入 LOCAL_LDLIBS := -llog 注意:一定要在include $(CLEAR_VARS)后面,否则无效。

 

当android开发调试的时间,调用这个函数将在androd调试输出信息

 

NDK对stl 的支持

在 Application.mk文件中加入 APP_STL := stlport_static,NDK编译半支持STL。加入后的文件内部如下

APP_ABI := all #编译所有硬件平台

APP_STL := stlport_static   #支持STL

 

C++文件比较多的项目NDK配置写法。

   在 Android.mk 文件的 LOCAL_SRC_FILES 加入类似下面内容,可实现多C++文件编译。

LOCAL_SRC_FILES := a.cpp a.cpp c.cpp d.cpp 

Linux C++,so动态库 示例实例 Linux C++,so动态库 示例实例 本文以Eclipse集成开发环境为例进行说明。 # 一、主要步骤 **(1)创建动态连接库(.so)工程** (1.1)建立.so工程; (1.2)添加MyHelloworld.cpp、MyHelloworld.h文件 (1.3)添加 -fPIC编译选项 (1.4)新增自定义成员函数:PrintHelloWorld函数 ............ 阅读详情

相关推荐

Android NDK编译实战:CMakeLists配置与so生成全解析

本文详细解析Android NDK编译实战中CMakeLists.txt的配置方法,重点讲解add_library指令、多so文件编译、target_link_libraries依赖管理以及第三方so库集成。通过实际案例演示如何高效生成so文件,提升Android原生开发效率与项目可维护性。

a1b2c3d的博客 684

Android C++ OpenGL 教程

用纯C++实现Android的OpenGL渲染功能,包括EGL环境创建、EGL线程创建、OpenGL生命周期管理等,会结合SurfaceView和TextureView实现OpenGL的渲染,最终我们会实现一个YUV播放器实例,为音视频开发打下坚实的基础。

用C在安卓手机上开发

在安卓手机上进行C语言开发需要一些特定的工具和设置。通常,C语言用于编写安卓的底层代码,如性能关键的模块或与硬件直接交互的部分。我们可以使用Android NDK(Native Development Kit)来开发这些部分。以下是如何在安卓手机上使用C进行开发的详细步骤。

zhumin726的专栏 2841

C++编写、生成、调用so库详解(一)

开发中经常会用到so库,大多是调用第三方的so库,偶尔也需要自己封装一个so库给别人调用,这边就记录一下开发so库的一个过程.首先我们这边是在Android Studio中开发的,所以仅描述在Android环境下开发过程,当然也可以用其他工具开发.

田一一的博客 5484

Android so库开发——Android Studio生成so库(一)

1)新建项目选择最下面的 Native C++ 下一步即可2)填写项目信息3)选择C++版本可以直接选择默认。

小旭的专栏 6926

Android开发中.so文件生成与调用完整指南

Android原生开发通过JNI(Java Native Interface)与C/C++代码交互,实现高性能计算和底层系统调用。在这一过程中,.so文件(共享对象)作为编译后的原生库,承载着关键的本地函数实现。它不仅提升了应用的执行效率,还广泛应用于图像处理、音视频编解码、AI算法加速等场景。与NDK(Native Development Kit)结合使用,开发者可以为不同CPU架构(如armeabi-v7a、arm64-v8a)编译适配的.so文件,从而实现跨平台兼容与性能优化。

weixin_42581003的博客 1379

c++封装so库,供安卓android调用

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录前言一、pandas是什么?二、使用步骤1.引入库2.读入数据总结 前言 提示:这里可以添加本文要记录的大概内容: 例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。 提示:以下是本篇文章正文内容,下面案例可供参考 一、pandas是什么? 示例:pandas 是基于NumPy 的一种工具,该工具是为了解决数据分析任务而创建的。 二、使用步骤 1.引入库 代码

刚入视频监控行业的菜鸡2090741348 8782

信号完整性基础04:串扰(1)

我们理解了“单个”传输线(传输线是信号路径+回流路径,切记~),但大多数情况下单独“传输线”的情况并不多见(理想情况下的同轴线缆可以算一个),大多数我们PCB板上有成百上千条走线,它们组成了一个“大社会”,就如当年的TVB神剧《创世纪》一样,到处充满着恩怨情仇;稍处理不慎,单板这个“社会”就会崩溃。那么我们要从哪里入手去理解它呢?最基本的就是从两条PCB走线(传输线)之间的串扰开始。好,年前倒数第二章:《为什么会有串扰》。 ps:我们了解了x射线是啥,那么今天开始讲“放射线”,这两种东西是否就是同一种呢~

WKEZHENG的博客 6034

在Android中,将 .cpp 文件编译成共享库(.so 文件)

一般在AS你新建C++项目会默认如下结构目录,要是用现有项目,你也可以手动创建。点击 Android Studio 顶部的。文件中,确保添加 CMake 的支持。的文件,该文件包含编译共享库的指令。,因为在JNI开发中,看到过它的影子。在 cpp 文件夹中创建一个名为。过时了,一般在老项目中比较常见。按钮,确保你的项目能够识别。在 app 目录下的。

WriteBug001的博客 1415

数据仓库的复用性:设计和构建一个高复用性的数仓

数据仓库的复用性是指在数据仓库的设计和使用过程中,能够实现数据、模型、流程、工具等多个层面的重复利用,减少重复开发,提高开发效率,降低维护成本,并增强灵活性和可扩展性。

z1941563559的博客 1307

SpaceMesh Mining 教程

當參與Spacemesh的用戶在完成P盤工作後需要完成兩個部分工作:PoET+PoST,這兩部分均是在不同的規定時間完成,具體可參考後續的時間表。註意!只有PoET和PoST均完成的用戶才可以獲得收益。Spacemesh相關P盤教程:說明:1.Spacemesh每個紀元epoch周期為14天,在8月7日完成PoET的將在8月20日完成PoST,收益將在8月25日後發放(之後用戶收益將每隔14天發放一次) 後續PoET時間為8月7日+N14 **後續PoST時間為8月20日+N。

Yc Chan 的个人博客 1045

Android 通过JNI调用三方so 高效教程

在Android开发中,JNI(Java Native Interface)技术允许Java代码与本地代码(如C/C++)进行交互,这是一种强大的功能,尤其在需要使用第三方本地库(.so文件)时。虽然网络上关于如何引入第三方.so文件和头文件的资料较多,但信息往往零散且缺乏清晰度。

m0_59162559的博客 2893

从零开始:用RFSOC XCZU47DR搭建软件无线电开发环境(2023最新版)

本文详细介绍了如何使用Xilinx RFSoC XCZU47DR搭建高性能软件无线电(SDR)开发环境,涵盖硬件选型、开发环境配置、射频子系统校准及实战应用开发。特别针对2023年最新技术需求,提供从基础配置到高级优化的完整指南,助力科研人员和工程师快速掌握RFSoC开发技术。

weixin_42525005的博客 512

Android Studio引入ndk编译的so库, 通过jni给Java程序使用

工作要求将一个C++老项目的函数用ndk打包成库给安卓同事的java程序调用。自己之前从来没接触过安卓开发,问了老板为什么不让安卓开发来干,老板说安卓开发不懂c++,公司就我一个是懂c++的。。。项目开发年限超过十年,只在32位系统编译过,一些32位可以通过的代码到了64位就不行了,很多的库多少有些兼容问题项目开发环境全程断网,给开发带来诸多不便NDK:Native Development Kit,是 Android 的一个工具开发包。

Tracker647的博客 2044

保姆级避坑指南:在openEuler 22.03 LTS上用kubeadm 1.32.2部署K8s集群(含阿里云镜像加速)

本文提供在openEuler 22.03 LTS上使用kubeadm 1.32.2部署Kubernetes集群的详细指南,涵盖系统准备、容器运行时适配、kubeadm配置及集群初始化等关键步骤。特别针对openEuler系统的特殊性,解决软件源配置、cri-dockerd编译安装、阿里云镜像加速等常见问题,帮助用户高效完成K8s集群部署。

weixin_28312391的博客 273

利用ADS建立MIPI D-PHY链路仿真流程

由于MIPI D-PHY的速率并不算高,因此,PCB设计难度通常不大,主要做好差分线的等长、阻抗的连续性、端口处的阻抗优化以及控制好走线的长度,拿到满意的结果还是较为轻松的,最后,建立流程化的仿真工程文件,可以保存为模板,方便日后的设计复用,非常方便。

一只豌豆象的博客 3571

NDK编译Android可用so文件

JNIEnv* env:指向JNI环境的指针,通过它可以访问JNI提供的许多函数,这些函数用于操作Java对象、字符串、数组等。JNIEnv* env,jobject /* this */是方法需要的特定参数,后边可以跟C中需要的参数然后调用C的方法。编译完成后会在app->build->intermediates->cxx内找到包含各种ABI的so文件。jobject:调用该方法的Java对象实例即javaClass的实例对象。javaFile:Java调用方法类名。JNIEXPORT:导出方法。

guo_chao_liu的博客 1645

virtuoso:layout如何做flat修drc

有些drc在virtuoso layout中修更节省时间,比如遇到一些via array需要做删改时,发现工具把via array做成了一个cell,如图。去改cell可能会影响很多via,所以最好的办法是做flat,去调整cut,比如删除。我正在「拾陆楼」和朋友们讨论有趣的话题,你⼀起来吧?

m0_61544122的博客 342

Android Studio的Android项目支持C++开发 (Android.mk配置)

Android Studio的Android项目支持C++开发 (Android.mk配置) 环境 主机:WIN7 开发环境:Android Studio2.2.2 步骤 安装NDK 打开Tools->Android-&gt...

eaway2009的专栏 1359

【OpenClaw从入门到精通】第09篇:企业级实践——将OpenClaw接入钉钉,打造7×24小时数字员工(2026实测版)

本文聚焦OpenClaw的企业级落地实践,以“招聘数字专员”为核心场景,完整演示从钉钉接入到全流程自动化的实现路径。内容涵盖企业级部署架构设计、前置环境搭建、核心技能开发、流程串联、安全权限管控及运维监控六大模块,详解简历解析、岗位匹配、外呼集成、CRM同步、日历提醒等关键技能的构建逻辑与代码实现。借鉴中关村科金、网易智企的企业级实践经验,重点突破企业知识融合、安全权限管控、业务系统连接三大核心门槛,提供可直接参考的配置示例与操作步骤。所有技术方案均基于公开文档与实测验证,兼顾新手入门与进阶实操。

专注于人工智能、软件开发、工控自动化、工厂数字化及智能化等领域,希望和大家共同进步! 1172

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

UE4安卓Gradle工程中的libUE4.so的生成原理

探究了UE4安卓Gradle工程中的libUE4.so的生成原理

sinat_23135151的博客 2552

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

Android NDK 集成调用第三方SO库(标准SO库和非标准SO库)

想要进阶高级Android开发工程师,NDK开发是必须要掌握的技能之一,本文以集成第三方SO库为开端,带大家入门NDK开发,主要包含一下内容:1、NDK工程创建;2、编写和打包Android标准SO库;3、集成Android标准SO库;4、集成Android非标准SO库。

sziitjin的博客 2733

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

Android so文件理解

一、so文件的概念 通常情况下,对函数库的链接是放在编译时期(compile time)完成的。所有相关的对象文件(object file)与牵涉到的函数库(library)被链接合成一个可执行文件(executable file)。程序在运行时,与函数库再无瓜葛,因为所有需要的函数已拷贝到自己门下。所以这些函数库被成为静态库(static libaray),通常文件名为“libxxx.a”的形式。 其实,我们也可以把对一些库函数的链接载入推迟到程序运行的时期(runtime)。这就是如雷贯耳的动态链接库(

分享Android开发知识 5296

llama.cpp 本地部署教程:手把手让大模型在安卓手机上跑起来,零基础上手 30 分钟搞定

你有没有过这种体验:手机上的 AI 助手,断网就罢工,隐私数据还得上传云端?今天带你用 llama.cpp 把大模型直接部署到安卓手机上,全程离线、数据不出设备,这就是端侧 AI 大模型推理最直接的落地方式。读完这篇,你能做到: - 用 Termux 在手机上本地编译 llama.cpp,一条命令跑通推理 - 用 Android NDK 交叉编译,在电脑上打包后推到手机运行 - 掌握 3 条性能

gitblog_01019的博客 796

Android | 第一个SO库

一、Android NDK开发 参考之前的博文: 项目记录 | Android NDK开发相关 二、Android SO库 参考之前的博文: 关于Android的SO库 三、第一个SO库制作 介绍一下如何往已有工程添加SO库。一起动手实践第一个SO库。主要的步骤如下: 3.1 在main目录下新建jni目录 3.2 找到项目的gradle.properties,添加一行 android....

【黑键】 265

使用VS(Visual Studio)生成能在安卓上运行的C++动态链接库

有时我们在网上克隆下来的C++项目是只能运行在PC上,不支持在安卓上运行,比如我工作中就遇到需要将ODE(Open Dynamics Engine)这个物理库迁移到安卓上,使得项目能调用ODE的代码,那么就可以使用VS将C++代码编译成一个安卓能调用的.so文件(类似Windows的DLL),采用这种方法的好处是不用下载Android Studio,而且VS傻瓜式的操作,让我们编译安卓项目变得更简单。 准备工作 1. 首先是下载VS,能搜到这里来的应该都下好了VS了吧,所以这里就不赘述了。以下我都是以Vi

K1ngRay的博客 6444
上一篇: 模拟TCP二进制流协议工具TcpEngine使用简介
下一篇: 数据流协议分析工具TcpEngine V1.1.0教程
display08
博客等级 码龄19年 49粉丝 18原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值