Android Studio之NDK开发(一)

前言

Android Studio2.2版本已经完全支持ndk开发了。而且默认采用CMake方式。
CMake优势不言而喻:
1. 可以直接的在C/C++代码中加入断点,进行调试
2. java引用的C/C++中的方法,可以直接ctrl+左键进入
3. 对于include的头文件,或者库,也可以直接的进入
4. 不需要配置命令行操作,手动的生成头文件,不需要配置android.useDeprecatedNdk=true 属性

一 . JNI 简介:

1.JNI是Java Native Interface的缩写,它提供了若干的API实现了Java和其他语言的通信(主要是C&C++)。从Java1.1开始,JNI标准成为java平台的一部分,它允许Java代码和其他语言写的代码进行交互。

这里写图片描述

2.使用场景:
2.1 避免使用JNI的时候,达到与本地代码进行交互的效果
  1. JAVA程序和本地程序使用TCP/IP或者IPC进行交互。
  2. 当用JAVA程序连接本地数据库时,使用JDBC提供的API
  3. JAVA程序可以使用分布式对象技术,如JAVA IDL API。

这些方案的共同点是,JAVA和C处于不同的线程,或者不同的机器上。这样,当本地程序崩溃时,不会影响到JAVA程序。

2.2 下面这些场合中,同一进程内JNI的使用无法避免:
  • 程序当中用到了JAVA API不提供的特殊系统环境才会有的特征。而跨进程操作又不现实。
  • 你可能想访问一些己有的本地库,但又不想付出跨进程调用时的代价,如效率,内存,数据传递方面。
  • JAVA程序当中的一部分代码对效率要求非常高,如算法计算,图形渲染等。
    总之,只有当你必须在同一进程中调用本地代码时,再使用JNI
2.3 JNI缺陷和作用:
  • 缺陷:
    一旦使用JNI,JAVA程序就丧失了JAVA平台的两个优点:
    1、程序不再跨平台。要想跨平台,必须在不同的系统环境下重新编译本地语言部分。
    2、程序不再是绝对安全的,本地代码的不当使用可能导致整个程序崩溃。一个通用规则是,你应该让本地方法集中在少数几个类当中。这样就降低了JAVA和C之间的耦合性

  • 作用:
    JNI可以这样与本地程序进行交互:
    1、你可以使用JNI来实现“本地方法”(native methods),并在JAVA程序中调用它们。
    2、JNI支持一个“调用接口”(invocation interface),它允许你把一个JVM嵌入到本地程序中。本地程序可以链接一个实现了JVM的本地库,然后使用“调用接口”执行JAVA语言编写的软件模块。

二. NDK 是什么?

Android NDK 是一套允许使用原生代码语言(例如 C 和 C++)实现部分应用的工具集。在开发某些类型应用时,这有助于重复使用以这些语言编写的代码库。

官方对于NDK是这样说的:

NDK 不适用于大多数初学的 Android 编程者,对许多类型的 Android 应用没什么价值。 因为它不可避免地会增加开发过程的复杂性,所以通常不值得使用。 但如果您需要执行以下操作,它可能很有用:
- 从设备获取卓越性能以用于计算密集型应用,例如游戏或物理模拟;
- 重复使用您自己或其他开发者的 C 或 C++ 库。

使用NDK好处:
  1. 代码的保护。由于apk的java层代码很容易被反编译,而C/C++库反汇难度较大;
  2. 可以方便地使用现存的开源库。大部分现存的开源库都是用C/C++代码编写的;
  3. 提高程序的执行效率。将要求高性能的应用逻辑使用C开发,从而提高应用程序的执行效率;
  4. 便于移植。用C/C++写得库可以方便在其他的嵌入式平台上再次使用。
NDK以及所需构建工具简介
CMake:外部构建工具;
  • CMake是一个开源的跨平台系列工具,旨在构建,测试和打包软件。
  • CMake用于使用简单的平台和编译器独立的配置文件来控制软件编译过程,并生成可以在选择的编译环境中使用的本地makefile和工作空间。
  • CMack工具套件由Kitware创建,以响应对开源项目(如ITK和VTK)的强大的跨平台构建环境的需求。
LLDB:Android Studio 上面调试本地代码的工具
  • LLDB是下一代高性能调试器。它被构建为一组可重用的组件,可以高度利用较大的LLVM项目中的现有库,例如Clang表达式解析器和LLVM反汇编程序。

  • 在Mac OS X中,LLDB是Xcode中的默认调试器,支持在桌面和iOS设备和模拟器上调试C,Objective-C和C ++。

  • LLDB项目中的所有代码都可以使用标准的 LLVM许可证(一种开放源代码“BSD风格”)许可证。

  • LLDB目前将调试信息转换成clang类型,以便它可以利用clang编译器基础架构。这允许LLDB在表达式中支持最新的C,C++,Objective C和Objective C ++语言特性和运行时间,而无需重新实现任何此功能。在编写表达式的函数,拆卸指令和提取指令详细信息等时,还可以利用编译器来处理所有ABI细节。

主要优点包括:
1. C,C ++,Objective C的最新语言支持 ;
2. 可以声明局部变量和类型的多行表达式;
3. 支持时使用JIT表达式;
4. 当JIT不能使用时,评估表达式中间表示(IR);

三. NDK 配置

下载安装NDK有两种方式:
1.手动下载,解压,配置目录。
2.Android Studio 自动完成。
第一种:
ndk 下载地址:
https://developer.android.google.cn/ndk/downloads/index.html
下载完成后,解压本地目录,在AS中配置路径即可:
这里写图片描述

推荐第二种:
1.点击Project Structure,选择 Download Android NDK;
这里写图片描述
2.下载完成后,AS自动配置;

简单了解下NDK各个目录作用:
- docs: 帮助文档
- build/tools:linux的批处理文件
- platforms:编译c代码需要使用的头文件和类库
- prebuilt:预编译使用的二进制可执行文件
- sample:jni的使用例子
- source:ndk的源码
- toolchains:工具链
- ndk-build.cmd:编译打包c代码的一个指令,需要配置系统环境变量

配置构建工具以及调试工具

1.如下图所示,点击SDK Manager,选择下载安装CMake以及LLDB;
步骤:Ctrl+Alt+S 打开Setting 输入SDK ,进入Android SDK ,选择SDK Tools ,下载CMake和LLDB;
这里写图片描述

2.配置NDK 环境变量,这个跟JDK SDK一样样儿 的配置方式。
这里写图片描述

cmd直接输入ndk-build回车 出现以下信息说明配置成功
这里写图片描述

四 .创建一个NDK项目

创建

创建项目时,记得勾选下面的Include C++ support
这里写图片描述

一路Next,然后

这里写图片描述

  • C++ Standard:使用下拉列表选择您希望使用哪种 C++ 标准。选择 Toolchain Default 会使用默认的 CMake 设置;

  • Exceptions Support:如果您希望启用对 C++ 异常处理的支持,请选中此复选框。如果启用此复选框,Android Studio 会将 -fexceptions 标志添加到模块级 build.gradle 文件的 cppFlags 中,Gradle 会将其传递到 CMake;

  • Runtime Type Information Support:如果您希望支持 RTTI,请选中此复选框。如果启用此复选框,Android Studio 会将 -frtti 标志添加到模块级 build.gradle 文件的 cppFlags 中,Gradle 会将其传递到 CMake。

分析例子

这里写图片描述
从上图可看到,和以前唯一不同的就是多出了cpp目录以及External Build Files俩个目录,那么这俩个都有什么用呢?一起来看看。

  • cpp 目录存放所有 native code 的地方,包括源码,头文件,预编译项目等。对于新项目,Android Studio 创建了一个 C++ 模板文件:native-lib.cpp,并且将该文件放到了你的 app 模块的 src/main/cpp/ 目录下。这份模板代码提供了一个简答的 C++ 函数:stringFromJNI(),该函数返回一个字符串:”Hello from C++”

  • External Build Files 目录是存放 CMake 或 ndk-build 构建脚本的地方。有点类似于 build.gradle 文件告诉 Gradle 如何编译你的 APP 一样,CMake 和 ndk-build 也需要一个脚本来告知如何编译你的 native library。对于一个新的项目,Android Studio 创建了一个 CMake 脚本:CMakeLists.txt,并且将其放到了你的 module 的根目录下

从编译到运行示例 APP 的流程到底是怎样呢?
  1. Gradle 调用外部构建脚本,也就是 CMakeLists.txt;
  2. CMake 会根据构建脚本的指令去编译一个 C++ 源文件,也就是native-lib.cpp,并将编译后的产物扔进共享对象库中,并将其命名为 libnative-lib.so,然后 Gradle 将其打包到 APK 中;
  3. 在运行期间,APP 的 MainActivity 会调用 System.loadLibrary() 方法,加载 native
    library。而这个库的原生函数,stringFromJNI(),就可以为 APP 所用了;
  4. MainActivity.onCreate() 方法会调用 stringFromJNI(),然后返回 “Hello from
    C++”,并更新 TextView 的显示;

    特别注意:Instant Run 并不兼容使用了 native code 的项目。Android Studio 会自动禁止 Instant Run 功能。

如果你想验证一下 Gradle 是否将 native library 打包进了 APK,你可以使用 APK Analyzer:
1. 选择 Build > Analyze APK。
2. 从 app/build/outputs/apk/ 路径中选择 APK,并点击 OK。
如下图,在 APK Analyzer 窗口中,选择 lib//,你就可以看见 libnative-lib.so
这里写图片描述

看一下代码:

按照示例写一个求和方法:
1.getSum()报错,Alt+Enter 第一行跳入

这里写图片描述

2.自动生成该文件
CPP文件里AS依然保持着自动提示,非常给力!
一定要注意extern “C”要移动到Line3,并加上一对大括号Line3,Line22包裹起来 ,图示的位置 编译没问题 运行会报错的。因为CMake在编译C++代码的时候把刚才新建的C++函数漏掉了,怎么把他加上呢?确保所有Java需要调用的C方法都放在extern “C”中,这样CMake才会帮我们正确编译。
这里写图片描述

运行后界面:
这里写图片描述

工程跑通了,下一步就要生成.so提供他人使用,详见下一篇博客NDK开发(二)

这里先提一下CMake.txt文件
这个文件#开头的全是注释,里面不是注释的只有下面的内容。

cmake_minimum_required(VERSION 3.4.1) #指定cmake版本


add_library( #生成函数库的名字
             native-lib  
             SHARED  #生成动态函数看
             src/main/cpp/native-lib.cpp ) #依赖的cpp文件

find_library( #设置path变量的名称
              log-lib
              #指定要查询库的名字
              log ) #在ndk开发包中查询liblog.so函数库(默认省略lib和.so),路径赋值给log-lib

target_link_libraries( #目标库,和上面生成的函数库名字一至
                       native-lib
             #连接的库,根据log-lib变量对应liblog.so函数库
                       ${log-lib} )

参考翻译:http://blog.csdn.net/wl9739/article/details/52607010

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值