刚接触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的字样。证明调用成功。

NDK编译第三方库,通过JNI调用。相关推荐

  1. opencv4.1无法加载python-cnn模型,编译第三方库libtensorflow_cc.so巨坑

    两个月前同事在python下训练的cnn模型(加了batchnorm层.dropout层,模型是.pb结尾),但发现opencv不支持加载(可能是这样).于是我找啊找,发现可以自己编译第三方库libt ...

  2. c调用python第三方库_c/c++调用python程序且含tensorflow第三方库

    对于纯python程序而言,用c程序来调用是比较适合的,如果python程序中包含了其他第三方库,则调用极可能出错,且不易查明原因.如笔者曾用c程序调用包含tensorflow的python程序,有的 ...

  3. Android NDK 编译 三方库记录 及 jni库封装问题

    因工作需求, 要将原先的c++库跨平台编译,在Android上运行, 其依赖了几个第三方库, 也需要一起编译, 在此做个记录 所需工具(centos 系统上完成) 1. cmake 3.15.6 2. ...

  4. linux ndk编译静态库,Android开发教程:NDK编译静态库失败

    Android---NDK编译静态库失败 Android.mk 相关编译文件: include $(CLEAR_VARS) LOCAL_MODULE    := libdvnca LOCAL_SRC_ ...

  5. matlab函数编译成库供C++调用(非常详细)

    MATLAB具有着很高的计算性能,一些算法用MATLAB很容易实现,而用C++很难实现,如果想在C++中调用MATLAB编写的函数,可以将该函数编译成库文件,之后在C++中对其进行调用. 本文详细讲解 ...

  6. Android NDK开发——Android studio使用JNI调用OpenCV处理图像

    前言 这里要演示的是使用Android studio 做APP开发,使用JNI与C++交互的demo. 一.创建工程 1.创建一个Native C++工程. 2.命令工程和指定交互语言. 3.指定C+ ...

  7. 【学习Android NDK开发】Java通过JNI调用native方法

    参考:Android NDK,sample/hello-jni示例项目 系统环境:Ubuntu 12.04 LTS 32-bit 1.准备工作 打开Eclipse,新建Android项目: Appli ...

  8. linux ndk编译so,有的APP NDK 编译的SO文件 无法调用 PackageManager

    反馈BUG之前,先issue里面搜看看有没有别人已经反馈过,重复的不予处理!! 问题描述 最近下了一个不可描述APP,实机是能运行的,不过在VXP里则报如下错误 07-14 15:48:28.672 ...

  9. 【Android开发】:在任意目录执行NDK编译

    2019独角兽企业重金招聘Python工程师标准>>> 文以简单的例子讲述如何在任意目录把自己写的C代码使用NDK提供的交叉编译该工具来编译成Android可使用的静态库/动态库. ...

最新文章

  1. apache +mod_jk URL中文乱码
  2. CentOS7.2 部署Ceph分布式存储
  3. hdu2609 How many
  4. 自定义taglib引入失败_小程序拼团总失败?看看微信官方和开发者们怎么说
  5. 《数学建模:基于R》——1.1 数据的描述性分析
  6. 铁道部2012年版全国72个铁路枢纽城市
  7. python画聚类图_python绘制的聚类图Python的局部变量和全局变量使用解惑
  8. 4.5亿!依图的AI芯片计划初步浮出水面
  9. python ios自动化_iOS python 自动化构建打包脚本
  10. Avast! 4 Server 服务器版license许可文件获得方法
  11. FGUI弧形UI实现
  12. c# Dll反编译查看原文件
  13. Matlab Coder将m文件转换成C/C++
  14. CAJ格式文件怎么转换为PDF格式
  15. 一文快速了解MaxCompute
  16. java中怎样实现登陆界面_JAVA登陆界面的实现(一)
  17. Linux Bind 安装
  18. 2.Echart----绘制饼图
  19. MySQL第一讲-mysql的基本框架和查询命令流程
  20. 各种常用默认的端口号

热门文章

  1. AG1KLP Q48 FPGA
  2. 网易公开课[一万分钟]《office办公达人养成计划》
  3. 新能源汽车充电标准--------简记
  4. COLING'22 | MetaPrompting:基于元学习的soft prompt初始化方法
  5. CVPR2023 目标检测论文合集
  6. 通过CSS进行SEO优化
  7. android代码密码隐藏,android 显示密码和隐藏密码
  8. Element的input密码框小眼睛(点击眼睛显示密码,再次点击图标隐藏密码)
  9. 铁威马NAS教程之jellyfin影音媒体库搭建指南
  10. 高级解决方案专家吴帆:元宇宙与智慧城市管理 l 华坤道威专访