NDK编译第三方库,通过JNI调用。

本文详细介绍了如何使用NDK编译第三方库,并通过JNI封装在Android平台上实现调用的过程。涵盖了环境搭建、动态库制作、JNI封装及Android工程集成等关键步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

刚接触NDK,JNI的知识,在网上找了很久的资料。各种版本的讲解让人眼花缭乱,下面我来介绍一下怎样通过NDK编译第三方库,然后经过JNI封装,最后在android平台上实现调用。

写着玩,大神勿喷。如有雷同纯属虚构。

如何在android平台上调用别人给你的动态库呢,NDK是必不可少的,我用的是R8版本的(R7之后就不用同时再装cygwin了,很方便)。首先第三方动态库要是for arm的,因为android底层就是linux的东西,最终要在android模拟器上运行。

开始前要多说明的一些东东:

(1)自己动手做一个动态库来模拟第三方动态库,很多人这里会用linux的系统默认安装的GCC来编译,后面就悲剧了,调用的时候直接弹出incompatible target 不兼容目标,因为linux 自带的GCC编译出来的是X86架构的,我们需要ARM架构的库,后来才知道要用交叉编译,还是要用NDK里面的交叉编译工具才行。

(2)PC机上要装有linux虚拟机(我版本是的是ubuntu,反正你要有这个环境。),然后你自己PC机上eclipse里的android开发环境(JDK+SDK+NDK)要搭建好,对了,最重要的NDK,这里给出安装说明链接http://wenku.baidu.com/view/76910ce2551810a6f52486a2.html这里是r7的。相比以前的版本,真心太方便了。

第一步:制作第一个linux下的动态库来模拟第三方动态库

(1)上面说了环境搭建好了之后,现在我们来从NDK中分离出独立的工具链,这样我们在制作第三方动态库的时候就不用写makefile了,首先你的linux环境必须装有linux版本的NDK“android-ndk-r8e-liunx-x86.zip”,(上面说的android平台里的NDK的是windows版的NDK“android-ndk-r8e-windows-x86.zip”,也就是说你要下两个版本的NDK。got it?)

(2)在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 加到文件的最后一行(这句什么意思?大神可以略去本人下面的赘述。简单说就是设置这个环境变量后,你后面执行arm-linux-androideabi-gcc这个命令时就会自动在:/home/laijingquan/toolchain/arm-linux-androideabi/bin这个目录里去寻找。)接着再执行 $ source /etc/profile 让环境变量立即生效。麻烦吗?我也觉得麻烦。痛苦过后就是更加痛苦。

(3)好,现在开始写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

(4)我们的目的是将它编译成库文件,将写好的.h和.c放在linux下的自建的文件夹,我的目录是/home/machaojie/jni ,jni里面有写好的.h和.c了,(这里可以用NDK-BUILD编译但是要写MAKEFILE,由于我分离了独立的编译工具,所以不用写MAKEFILE直接编译就行了)。

在linux终端输入命令 cd /home/laijingquan/jni ,arm-linux-androideabi-gcc -c Add.c 你会发现jni里有Add.o(目标文件,编译-链接。编译的基本步骤),然后执行 arm-linux-androideabi-gcc -shared -fPCI -o libmyAdd.so Add.o(-shared -fPCI -o libmyAdd.so Add.o 之间都是有空格的)最后在jni文件夹会生成libmyAdd.so的动态库。OK,linux虚拟机下的工作做完了,现在回到我们的PC机上吧。

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

上面花了很多时间了,开始也说了因为网上几乎找不到这样的文章,所以我啰嗦一下。好!重头戏来了,睁大眼睛!。。。。。。我们的目的是将第三方动态库打包进APK在android模拟器运行。

如何实现呢,这里要说到JNI,第三方动态库必须经过JNI封装后才能被android使用,具体知识这里我就不仔细说了(你可以把JNI看做java和C-C++之间的桥梁,通过JNI的几步操作可以让java调用C-C++实现的程序),下面我们来说说怎么做。

新建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格式的头文件。

然后在在PC机上通过cmd-控制台窗口进入该工程的src目录
运行如下命令
> javac com\android\libjni\LibJavaHeader.java
> javah com.android.libjni.LibJavaHeader

(这里又涉及到java环境的配置,java jdk你要装上,接着自己配置几个环境变量。网上有,也很简单,自己搜一下。)

此时在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文件

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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值