Android实战技巧之四十五:复用原有C代码的方案
2015-11-03 16:57
696 查看
任务描述
有一套C写的代号为“Shooter”的核心算法库可以解决我们面临的一些问题,只是这个库一直用在其他平台。我们现在的任务是将其复用到Android平台上。
复用方案描述
示意图如下编译Android下的Shooter.so
共享库是不能跨平台的,我们首要的工作就是用交叉编译器将原Shooter库编译成可在Android平台下使用的so。Android下常用cpu架构是ARM,现在X86也多了起来,为了兼容多平台,我们要应对几款不同的cpu架构。下面就先来演示ARM下的交叉编译。1、安装交叉编译工具
$ /opt/ndk/android-ndk-r10b/build/tools/make-standalone-toolchain.sh Auto-config: --toolchain=arm-linux-androideabi-4.6 Copying prebuilt binaries... Copying sysroot headers and libraries... Copying c++ runtime headers and libraries... Creating package file: /tmp/ndk-linc/arm-linux-androideabi-4.6.tar.bz2 Cleaning up... Done.
将其解压到你喜欢的位置(我放到了~/bin/build-tools/arm-linux-androideabi-4.6/),这样就可以工作啦。
2、Shooter源码重编译
请参考《做一个动态链接库》
gcc的编译指令。
Shooter库在Android下的调式请参考《Android实战技巧之四十四:Hello,Native!》
下面将shooter源码编译:
$ ~/bin/build-tools/arm-linux-androideabi-4.6/bin/arm-linux-androideabi-gcc -c -fPIC -o ./arm/shooter.o shooter.c $ cd arm/ $ ~/bin/build-tools/arm-linux-androideabi-4.6/bin/arm-linux-androideabi-gcc -shared -o libshooter.so shooter.o $ ll total 20 drwxrwxr-x 2 linc linc 4096 11月 1 13:49 ./ drwx------ 3 linc linc 4096 11月 1 13:47 ../ -rwxrwxr-x 1 linc linc 5932 11月 1 13:49 libshooter.so* -rw-rw-r-- 1 linc linc 1764 11月 1 13:48 shooter.o
tips:
将此工具路径加到环境变量中吧。
shooterProxy
JNI技术是联系Java和Native世界的桥梁,它由Java端和Native端构成。1、ShooterProxy.java
package com.linc.lib; public class ShooterProxy { /* static { System.loadLibrary(ShooterProxy); } */ public static native int A(int a); }
编译后再用javah工具生成c头文件,参考:
第一个NDK程序
http://blog.csdn.net/lincyang/article/details/6705143
2、ShooterProxy.c
根据com_linc_lib_ShooterProxy.h,编写c源文件。
#include "com_linc_lib_ShooterProxy.h" //#include <stdio.h> #include "shooter.h" #include <android/log.h> #define LOG_TAG "ShooterProxy:" //#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__) #define LOGD(...) ((void)__android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)) JNIEXPORT jint JNICALL Java_com_linc_lib_ShooterProxy_A (JNIEnv *env, jclass obj, jint i) { //call shooter lib LOGD("method A() called! i: %d",i); if(i>0) return 54321; else { int result = A(0); LOGD("call shooter A method.result:%d",result); return result; } }
注意Android.mk的写法:
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := ShooterProxy LOCAL_SRC_FILES := ShooterProxy.c LOCAL_LDLIBS := ./armeabi-v7a/libshooter.so #LOCAL_LDLIBS := -llog -landroid -lEGL -lGLESv1_CM #LOCAL_STATIC_LIBRARIES := android_native_app_glue LOCAL_LDLIBS += -llog -ldl include $(BUILD_SHARED_LIBRARY)
编译:
$ ndk-build Android NDK: WARNING:/home/linc/workspace/csdn_code/reusec/reuse-C/jni/Android.mk:ShooterProxy: non-system libraries in linker flags: ./armeabi-v7a/libshooter.so Android NDK: This is likely to result in incorrect builds. Try using LOCAL_STATIC_LIBRARIES Android NDK: or LOCAL_SHARED_LIBRARIES instead to list the library dependencies of the Android NDK: current module [armeabi-v7a] Compile thumb : ShooterProxy <= ShooterProxy.c [armeabi-v7a] SharedLibrary : libShooterProxy.so [armeabi-v7a] Install : libShooterProxy.so => libs/armeabi-v7a/libShooterProxy.so
此时我们有了两个so文件,一个是libshooter.so,一个是libShooterProxy.so。接下来我们在App中动态加载这两个动态库。
应用中调用ShooterProxy
就用一个最最简单的例子来做此事好了,一个TextView在Activity启动时调用A方法。11-03 16:05:29.240 11203-11203/com.linc.shooterdemo D/ShooterProxy:: method A() called! i: 0 11-03 16:05:29.240 11203-11203/com.linc.shooterdemo D/ShooterProxy:: call shooter A method.result:4
比较遗憾的是,我的设备虽然root,但是stdout重定向后也没能在logcat中看到输出。重定向方法如下:
$ adb root adbd is already running as root $ adb shell stop $ adb shell setprop log.redirect-stdio true $ adb shell start
尾声
这篇文章早在今年6月份就开始起草,但事情一多就给耽搁了。后来的经历也让我意识到,使用第三方so并没有那么简单,我们需要在ShooterProxy这一层做很多事情。
这里面要遇到很多Java与C的数据类型转换,C中要使用Java中的类等等事情,扎实的JNI功底才是本项目成功的关键。
所以,Java与C/C++复合型人才很适合这个领域。
源码在这里!
参考:
http://blog.csdn.net/jiangxuchen/article/details/22883575
http://blog.csdn.net/lincyang/article/details/6705143
http://blog.csdn.net/lincyang/article/details/44725529
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析
- android searchView的关闭事件
- SourceProvider.getJniDirectories