前言
其实参考超级简单的Android Studio jni实现 这篇文章就可以完美的实现,java代码调用c++代码。
记得先下载ndk的官方包。
步骤
1.到谷歌官方网站下载NDK
2.接着按照文中的步骤一步步完成即可。
3.对一些文件进行解释
JNI(Java Native Interface):Java本地接口。是为了方便Java调用c、c++等本地代码所封装的一层接口(也是一个标准)。大家都知道,Java的优点是跨平台,但是作为优点的同时,其在本地交互的时候就编程了缺点。Java的跨平台特性导致其本地交互的能力不够强大,一些和操作系统相关的特性Java无法完成,于是Java提供了jni专门用于和本地代码交互,这样就增强了Java语言的本地交互能力。上述部分文字摘自任玉刚的 Java JNI 介绍
NDK(Native Development Kit) : 原生开发工具包,即帮助开发原生代码的一系列工具,包括但不限于编译工具、一些公共库、开发IDE等。
NDK工具包中提供了完整的一套将 c/c++ 代码编译成静态/动态库的工具,而Android.mk和Application.mk,你可以认为是描述编译参数和一些配置的文件。比如指定使用c++11还是c++14编译,会引用哪些共享库,并描述关系等,还会指定编译的abi。只有有了这些NDK中的编译工具才能准确的编译 c/c++ 代码。
那 CMake 又是什么呢。脱离 Android 开发来看,c/c++ 的编译文件在不同平台是不一样的。Unix 下会使用 makefile 文件编译,Windows 下会使用 project 文件编译。而 CMake 则是一个跨平台的编译工具,它并不会直接编译出对象,而是根据自定义的语言规则(CMakeLists.txt)生成 对应 makefile 或 project 文件,然后再调用底层的编译。
在Android Studio 2.2 之后,工具中增加了 CMake 的支持,你可以这么认为,在 Android Studio 2.2 之后你有2种选择来编译你写的 c/c++ 代码。一个是 ndk-build + Android.mk + Application.mk 组合,另一个是 CMake + CMakeLists.txt 组合。这2个组合与Android代码和c/c++代码无关,只是不同的构建脚本和构建命令。本篇文章主要会描述后者的组合。(也是Android现在主推的)
- ABI 是什么
ABI(Application binary interface)应用程序二进制接口。不同的CPU 与指令集的每种组合都有定义的ABI
(应用程序二进制接口),一段程序只有遵循这个接口规范才能在该 CPU 上运行,所以同样的程序代码为了兼容多个不同的CPU,需要为不同的ABI
构建不同的库文件。当然对于CPU来说,不同的架构并不意味着一定互不兼容。
armeabi设备只兼容armeabi;
armeabi-v7a设备兼容armeabi-v7a、armeabi;
arm64-v8a设备兼容arm64-v8a、armeabi-v7a、armeabi;
X86设备兼容X86、armeabi;
X86_64设备兼容X86_64、X86、armeabi;
mips64设备兼容mips64、mips;
mips只兼容mips;
具体的兼容问题可以参见这篇文章。Android SO文件的兼容和适配
当我们开发 Android 应用的时候,由于 Java 代码运行在虚拟机上,所以我们从来没有关心过这方面的问题。但是当我们开发或者使用原生代码时就需要了解不同ABI
以及为自己的程序选择接入不同ABI
的库。(库越多,包越大,所以要有选择)
了解完 armeabi armeabi-v7a arm64-v8a mips mips64x86x86_64等abi的原理,会发现要想兼容所有cpu的abi必定会产生更大的apk文件,所以在这里直接简单粗暴的兼容armeabi就ok了,像微信就是这么粗暴的。
很多时候导很多abi的so文件还是会出现找不到so的情况,那么只兼容armeabi就可以了嘛!
在build.gradle的android里的defaultConfig内添加如下内容:
defaultConfig {
ndk {
abiFilters "armeabi"
}
}
或者再多加个armeabi-v7a都可以。
然后项目中只留armeabi就可以了。
如果报错
Error:(15, 1) A problem occurred evaluating project ':app'.
> Error: NDK integration is deprecated in the current plugin. Consider trying the new experimental plugin. For details, see http://tools.android.com/tech-docs/new-build-system/gradle-experimental. Set "android.useDeprecatedNdk=true" in gradle.properties to continue using the current NDK integration.
请在 gradle.properties 中 添加
android.useDeprecatedNdk=true
语法
Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := MyLibrary
LOCAL_SRC_FILES =: MyLibrary.cpp
include $(BUILD_SHARED_LIBRARY)
其中LOCAL_PATH是C/C++代码所在目录,也就是我们的jni目录。
LOCAL_MODULE是要编译的库的名称。编译器会自动在前面加上lib,在后面加上.so。
LOCAL_SRC_FILES是要编译的C/C++文件。
Application.mk
APP_ABI := all
表示生成所有平台的动态库。
配置gradle
在defaultConfig下,配置ndk:
ndk{
moduleName "MyLibrary" // 生成的so名字
}
在android标签内配置sourceSets:
sourceSets.main{
jni.srcDirs = []
jniLibs.srcDir "src/main/libs"}
}
生成的so文件都在src/main/libs目录下。
总结
遵循以下步骤可以将一个本地方法链接到Java程序中
1.在Java类中声明一个本地方法
2.运行javah以获得包含该方法的C声明的头文件
3.用C实现该本地方法
4.将代码置于共享库中
5.在Java程序中加载该类库
后面可以了解和学习一下cmake
参考文章
http://blog.csdn.net/chuhongcai/article/details/52558049
https://developer.android.google.cn/ndk/downloads/index.html#rel
http://www.jianshu.com/p/6332418b12b1
http://blog.csdn.net/wwj_748/article/details/51274580(命令行的方式)