用NDK调用第三方动态库

转自:http://blog.csdn.net/laijingquan/article/details/8950347

现在一些NDK调用第三方库都是一些旧环境旧工具所完成的,我来给大家更新一下吧。

首先讲讲大概一个流程吧,这篇文章主要是写给自己的,怕忘记了,大神勿喷。

 

如何在android平台上调用别人给你的动态库呢,NDK这工具帮了我很大的忙。首先我们要确定第三方动态库是for arm的,因为你要在手机(android模拟器)上运行,PC机是X86的 手机大多数(好像有INTEL要加进手机了,太高端,相信大家还是用ARM架构的模拟器吧)是ARM的。

自己动手做一个动态库来模拟第三方动态库,很多人这里会用LINUX的GCC来编译(我是菜鸟我就是这样做的),后面测试就悲剧了,调用的时候直接弹出incompatible target 不兼容目标,因为linux 自带的GCC编译出来的是X86架构的,我们需要ARM架构的库,后来知道要用交叉编译,所以下了一个arm-linux-gcc来编译,但是最终调用的时候会出现类似于缺失依赖库的问题,比如...could not load neeeded library for ......。最终还是用NDK里面的交叉编译工具才行。好了啰嗦了这么多,现在开始动手吧。

PS:PC机上要装有linux(我的是ubuntu12.0)环境,然后windows下android平台环境(JDK+SDK+NDK)要搭建好,做android开发的这些肯定已经搞好了,这里我唯一想说的就是NDK R8,它已经在里面集成linux环境了,所以现在可以直接解压就可以使用,不用再装什么cygwin了,很方便,本文就是用NDK R8来做的。这里给出安装说明链接http://wenku.baidu.com/view/76910ce2551810a6f52486a2.html是r7的

第一步:制作第一个linux下的动态库(因为android的底层就是linux)来模拟第三方动态库

上面说了环境搭建好了之后,现在我们来从NDK中分离出独立的工具链,这样我们在制作第三方动态库的时候就不用写makefile了,首先你的linux环境必须装有linux版本的NDK“android-ndk-r8e-liunx-x86.zip”,(上面说的android平台的理所当然是WINDOWS版的NDK“android-ndk-r8e-windows-x86.zip”)在linux命令解压压缩包得android-ndk-r8e,然后再linux终端进入android-ndk-r8e的根目录,$ build/tools/make-standalone-toolchain.sh --platform=<PLATFORM> --install-dir=<INSTALL_PATH>

按上述格式输入下面的命令

$ build/tools/make-standalone-toolchain.sh --platform=android-14 --install-dir=/home/xx/toolchain/arm-linux-androideabi/

这条命令的意思就是将交叉编译工具完整复制出来,android-14是你的API ,-dir后面是你要复制安装到的目录,执行完后你会发现在/home/xxx/下发现你新建的toolchain目录,到此我们已经从NDK中分离出独立的工具链了。最后为了方便我们需要设置一下环境变量,如果不设置,每次你都要这样写/home/xx/toolchain/arm-linux-androideabi/bin/arm-linux-androideabi-gcc -c Add.c 这样相当麻烦。在Linux终端输入 $ sudo -s 获取超级权限,再输$gedit /etc/profile 在弹出的profile文件里将以下内容:export PATH=$PATH:/home/laijingquan/toolchain/arm-linux-androideabi/bin 加到文件的最后一行(很多不理解最后一行什么意思,就是讲它作为profile文件的最后一行,好吧,让我2B一下吧,其实就是我不理解)再执行 $ source /etc/profile 让环境变量立即生效。虽然步骤有点麻烦,但是做好后,以后开发很方便。好,现在开始写C函数

很简单的函数,网上找的。

Add.c

#include <stdio.h>
int Add(int x, int y)
{
return x+y;
}
Add.h:


#ifndef _ADD_H_
#define _ADD_H_
int Add(int x, int y);
#endif

然后我们的目的就是讲它编译成库文件,将写好的.h和.c放在linux下的自建的文件夹,拿我的做例子,/home/laijiingquan/jni ,jni里面有写好的.h和.c了,(这里可以用NDK-BUILD编译但是要写MAKEFILE,由于我分离了独立的编译工具,所以不用写MAKEFILE直接编译就行了)在linux终端输入命令 $cd /home/laijingquan/jni ,然后$arm-linux-androideabi-gcc -c Add.c 你会发现jni里有Add.o(由于.so文件都是有.o文件生成,所以要先生成.o),然后执行 $arm-linux-androideabi-gcc -shared -fPCI -o libmyAdd.so Add.o(-shared -fPCI -o libmyAdd.so Add.o 之间都是有空格的)最后在jni文件夹会生成libmyAdd.so的动态库。好了linux下的工作做完了,现在转到WINDOWS上吧。

第二步:用NDK调用第三方动态库

上面花了很多时间了来讲怎么做动态库,因为网上几乎找不到这样的文章,所以我啰嗦了一下。好重头戏来了。我们的目的是将第三方动态库打包进APK给android运行。如何实现呢,这里要说到JNI,第三方动态库必须经过JNI封装后才能被android使用,具体知识我就不讲述了,我们来说说怎么做。PS:方法参考别人的,但它有些地方写错了,而且我和它的环境不同,我的是android-16,减少了一些步骤。这里我重新写一下。

新建android工程,模式如下,在com.android.libjni包下有两个JAVA文件,内容下面给出

 

libjni.java:

package com.android.libjni;
import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;

public class libjni extends Activity{
 public void onCreate(Bundle savedInstanceState){
  super.onCreate(savedInstanceState);
  int iResult = new LibJavaHeader().Add(5, 6);
  TextView tv = new TextView(this);
  tv.setText(Integer.toString(iResult));
  setContentView(tv);
 }
 

 static{
  
  System.loadLibrary("myAdd");
  System.loadLibrary("addjni");
 }
 
}

和LibJavaHeader.java:

package com.android.libjni;

public class LibJavaHeader {
 
 public native int Add(int x, int y);

}

 

 

第一个JAVA里调用了Add方法,实现两个加法,这是C语言的

第二JAVA是为了生成JNI格式的头文件。

 

然后

在命令行中进入该工程的src目录
运行如下命令
> javac com\android\libjni\LibJavaHeader.java
> javah com.android.libjni.LibJavaHeader

此时在src目录下生成了一个名为com_android_libjni_LibJavaHeader.h的头文件,
其内容如下:
com_android_libjni_LibJavaHeader.h:

#include <jni.h>
/* Header for class com_android_libjni_LibJavaHeader */

#ifndef _Included_com_android_libjni_LibJavaHeader
#define _Included_com_android_libjni_LibJavaHeader
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_android_libjni_LibJavaHeader
 * Method:    Add
 * Signature: (II)I
 */
JNIEXPORT jint JNICALL Java_com_android_libjni_LibJavaHeader_Add
  (JNIEnv *, jobject, jint, jint);

#ifdef __cplusplus
}
#endif
#endif

编写库的封装函数libaddjni.c

根据前面生成的com_android_libjni_LibJavaHeader.h 文件,编写libaddjni.c,用
来生成libaddjni.so

#include <jni.h>
#include "Add.h"
#include <com_android_libjni_LibJavaHeader.h>

 

#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_android_libjni_LibJavaHeader
 * Method:    Add
 * Signature: (II)I
 */
JNIEXPORT jint JNICALL Java_com_android_libjni_LibJavaHeader_Add(JNIEnv *jPE, jobject jo, jint jiX, jint jiY)
{
 return Add(jiX, jiY);
}

#ifdef __cplusplus
}
#endif

 

好了接下来就是写MK,prebuilt下makefiel如下

LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := myAdd
LOCAL_SRC_FILES := libmyAdd.so
TARGET_PRELINK_MODULES := false
include $(PREBUILT_SHARED_LIBRARY)
 

 

jni目录的MK如下

LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := addjni
LOCAL_SRC_FILES := libaddjni.c
LOCAL_SHARED_LIBRARIES := myAdd   
include $(BUILD_SHARED_LIBRARY)
include $(LOCAL_PATH)/prebuilt/Android.mk

Application.mk内容如下

APP_ABI := armeabi armeabi-v7a

 

好了现在可以编译了,设置一下build(装好NDK R8E前提下)右键LIBJNI文件夹,选中properties选项,然后选中Builders,点击NEW,选择program确定

NAME自己随便定一个,LOCATION就是找ndk-build.cmd的位置,用Browse File System,Working Directory就是工程目录下的jni用Browse Workspace

 

 

点击OK后 android会自动在lib 下生成两个.so文件

PS:其他文章说要将两个.so push进模拟器,所以还要装ADB 和ROOT模拟器,可能那时老环境下的操作,我这里不需要,直接运行即可。

运行模拟器,会看到11的字样。证明调用成功

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值