移植libev事件库到Android中

因为libev库是使用C语言写的,所以在Android项目中使用此库的方法是把libev编译成.so文件,在Android中使用jni方式来调用libev的.so文件。

我们大家都知道android的ndk开发可以编译c,c++代码,不过需要自己写Android.mk文件。但是对于大多数开源项目来说,代码量很大,而且在编译前需要通过configure来配置编译选项,这种情况下,自己写Android.mk文件是很不现实的。

在这里,先参考如何使用android独立工具链快速移植开源项目中的方法实现配置好Android交叉编译工具链。因为我需要把我的应用运行在x86和ARM平台的Android系统中,所以我通过文中的方法编译出了两种平台的.so文件,分别位于xxx/libev-4.19/android/x86/lib和xxx/libev-4.19/android/arm/lib下面。

接下来参考Android NDK编译本地文件以及引用第三方so文件 ,在jni目录下面新建prebuild文件夹。

Android NDK 编程中提供了编译不同平台.so文件的方法,在jni目录下面新建Application.mk文件,在文件中加入以下内容。

#APP_ABI := all
#APP_ABI := armeabi armeabi-v7a x86
APP_ABI := x86
APP_PLATFORM := android-17

其中APP_ABI指定了平台的类型,APP_PLATFORM指定了Android的版本。在Android NDK 编译本地代码的过程中会对$(TARGET_ARCH)分别赋不同的值,并执行Android.mk文件,生成对应平台的.so文件。比如当

APP_ABI := armeabi armeabi-v7a x86

时,在lib目录下面会生成如下文件夹:

在不同平台运行时,Android系统会自动加载不同的.so文件。

为了使Android系统编译不同平台时,加载不同的libev.so文件,我使用$(TARGET_ARCH)变量进行区分。在prebuild文件下面新建android.mk文件,

并把事先编译的x86和ARM平台的libev.so文件复制到prebuild文件夹中。这里要注意,在linux平台编译完成的libev库的后缀名是libev.so.4.0.0,但是android只能识别.so后缀的文件,我这里把libev.so.4.0.0改成了libev.so,这里有个隐患,后面会提到。

此时的目录结构如下:

prebuild中的Android.mk的内容如下:

include $(CLEAR_VARS)
ifeq ($(TARGET_ARCH) ,x86)
    include $(CLEAR_VARS)
    LOCAL_MODULE := ev-x86
    LOCAL_SRC_FILES := $(LOCAL_PATH)/prebuild/libev-x86.so
    include $(PREBUILT_SHARED_LIBRARY)
else
    include $(CLEAR_VARS)
    LOCAL_MODULE := ev-arm
    LOCAL_SRC_FILES := $(LOCAL_PATH)/prebuild/libev-arm.so
    include $(PREBUILT_SHARED_LIBRARY)
endif

这样,做到了区分不同的平台。

在jni目录下面的Android.mk内容如下:

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE    := conn
LOCAL_SRC_FILES := net_service.c 

ifeq ($(TARGET_ARCH) ,x86)
    LOCAL_SHARED_LIBRARIES := ev-x86
else
    LOCAL_SHARED_LIBRARIES := ev-arm
endif

LOCAL_LDLIBS+= -L$(SYSROOT)/usr/lib -llog
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include

LOCAL_CFLAGS := -D_ANDROID_
include $(BUILD_SHARED_LIBRARY)

include $(LOCAL_PATH)/prebuild/Android.mk

这里要注意设置LOCAL_SHARED_LIBRARIES 和include $(LOCAL_PATH)/prebuild/Android.mk,这样我的本地代码net_service.c才能访问libev库。在net_service.c中,我调用了libev中的函数。

通过这种方法,生成我的libconn.so,在Android实体机上运行,会出现以下错误:

可以看到在加载libconn.so后,然后起加载libev.so.4文件。但是我们的文件是libev-x86.so或者libev-arm.so,为什么会是libev.so.4呢。

这个问题我找了很久,最后我去看了一下在linux下make libev-4.19时的信息。信息如下:

从信息里找到了libev.so.4这个字符串,图中标注部分可以猜到大体意思,是把相关文件编译成了文件名为libev.so.4.0.0,但是soname为libev.so.4的一个so格式的文件。

这里关键词是soname,详细信息可以参考我对动态链接库的一些理解 ,大体来说就是soname是so文件的一个别名,因为我们在jni的主目录下的Android.mk中,加载了libev-x86.so文件(以下以x86平台为例),链接器生成libconn.so的时候,把libev-x86.so文件中的soname也就是libev.so.4放在了libconn.so的依赖中,当系统加载了libconn.so后,就会根据依赖信息去加载libev.so.4这个文件。而我们的文件名是libev-x86.so,所以会出现找不到libev.so.4的错误提示。

找到了原因,就知道解决办法了,解决办法就是把libev-86.so文件中的soname改成libev-x86.so,就这个简单。

具体方法如下:(以x86为例)

在libev-4.19源码文件夹下面执行configure进行配置

./configure --host=i686-linux-android --prefix=`pwd`/android/x86

执行make

此时根据信息,可以看到生成的文件在.libs下面,注意这是个隐藏目录。

进入.libs目录下面,目录结构如下:

这里的libev.so.4.0.0就是通过

生成的,因此我们在.libs目录下手工输入这个命令,生成soname为libev-x86.so的so文件,命令如下:

i686-linux-android-gcc -shared  -fPIC -DPIC  .libs/ev.o .libs/event.o   -lm  -O3   -Wl,-soname -Wl,libev-x86.so -o .libs/libev-x86.so

这样就生成了soname为libev-x86.so的libev-x86.so文件。

生成libev-arm.so文件的过程如上。

把libev-x86.so libev-arm.so文件复制到prebuild目录下面。这样生成的apk文件可以正常运行。

时间: 2024-11-10 16:41:44

移植libev事件库到Android中的相关文章

libev事件库使用笔记

源码下载地址:http://dist.schmorp.de/libev/ libev是一个高性能的事件循环库,比libevent库的性能要好. 安装: 1 tar -zxf libev-4.15.tar.gz 2 cd libev-4.15 3 ./configure 4 make 5 make install 设置环境变量: 设置一下环境变量(在文件/etc/profile中添加).然后才可以运行. 1 export LIBDIR=/usr/local/lib 2 export LD_LIBR

ffmpeg 解码库在android中的使用

<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">前面有博客讲到linux下编译ffmpeg</span> 那么编译完成之后应该怎么使用呢? 在参考了ffmpeg解码文件的demo这里给出一个解码的so库JNI实现方法 在编译完成ffmpeg的源码后,新建一个工程如下图目录结构 在ffmpeg编译后的源码中include文件

Android中的事件传递机制

Android源码版本:API Level 19(Android 4.4) Android事件构成 在Android中,事件主要包括点按.长按.拖拽.滑动等,点按又包括单击和双击,另外还包括单指操作和多指操作.所有这些都构成了Android中的事件响应.总的来说,所有的事件都由如下三个部分作为基础: 按下(ACTION_DOWN) 移动(ACTION_MOVE) 抬起(ACTION_UP) 所有的操作事件首先必须执行的是按下操作(ACTIONDOWN),之后所有的操作都是以按下操作作为前提,当按

android中的事件传递和处理机制

一直以来,都被android中的事件传递和处理机制深深的困扰!今天特意来好好的探讨一下.现在的感觉是,只要你理解到位,其实事件的 传递和处理机制并没有想象中的那么难.总之,不要自己打击自己,要相信自己能掌握这块知识.好了,下面是我今天的收获,希望也 能对你有一点帮助. 一.拟人化来理解android中的事件机制 其实android中的事件传递与处理机制跟我们生活中的事件处理是一样的.这里有一个生活中的例子,很能说明这个问题.阐述如下: 你是一个公司的员工,你的上头有一个主管,主管上头呢还有一个经

android 中 任务、进程和线程的区别

任务.进程和线程 关于Android中的组件和应用,之前涉及,大都是静态的概念.而当一个应用运行起来,就难免会需要关心进程.线程这样的概念.在Android中,组件的动态运行,有一个最与众不同的概念,就是Task,翻译成任务,应该还是比较顺理成章的. Task的介入,最主要的作用,是将组件之间的连接,从进程概念的细节中剥离出来,可以以一种不同模型的东西进行配置,在很多时候,能够简化上层开发人员的理解难度,帮助大家更好的进行开发和配置. 任务 在SDK中关于Task(guide/topics/fu

cceditbox和cocostudio联合界面点击事件无响应问题,Android中创建文件夹问题

这两个问题折腾了我一天多时间,尽快下班时候把创建文件夹问题给解决了,刚把cceditbox点击事件无响应问题解决了.真是大爽. 1.创建文件夹 _mkdir()这个c函数就行,在vs ide中,定位的头文件是direct.h,但是这个文件不被ndk编译通过,没有这个文件.好吧,死脑筋,开始怀疑eclipse库路径设置有问题,但是不知道哪不对,搜索到了头大地步,好吧,认真仔细一看,原来是在ndk中,_mkdir函数放在了#include <sys/stat.h>中,改为这个头文件就行了. 2.点

关于android中事件传递和分发的一些小理解

android中 当我们的手指触摸屏幕将产生一个事件, (假设 这个过程中如果没有显示的去拦截该事件的话)   这个事件会逐级传递到视图的最底层,即使在中间某些视图会响应这个事件( 这个视图也不会去消费这个事件),     仍然是会传递到底层(底层不响应该事件),然后再由底层回传到顶层,在传回顶层的过程中 ,   原先会响应该事件的视图才会去消费这个事件 例如在左图中                                 A                               

【转】Android中的事件分发和处理

原文链接:http://www.apkbus.com/home.php?mod=space&uid=705730&do=blog&id=61207 上次跟大家分享了一下自定义View的一下要点,这次跟大家聊一下View的事件分发及处理,为什么主题都是View,因为作为一名初级应用层Android工程师,跟我打交道最多的莫过于各种各样的View,只有详细了解他们各自的习性,才能更好地跟他们沟通交流,做出自己想要的效果. 基础储备 View.MotionEvent 我们都能详细地说出A

Android中的事件分发机制(下)——View的事件处理

综述 在上篇文章Android中的事件分发机制(上)--ViewGroup的事件分发中,对ViewGroup的事件分发进行了详细的分析.在文章的最后ViewGroup的dispatchTouchEvent方法调用dispatchTransformedTouchEvent方法成功将事件传递给ViewGroup的子View.并交由子View进行处理.那么现在就来分析一下子View接收到事件以后是如何处理的. View的事件处理 对于这里描述的View,它是ViewGroup的父类,并不包含任何的子元