Android NDK开发(一)  入门

96
changer0
2.5 2016.10.30 00:15* 字数 1439

开始之前

最近学习了一下NDK的开发, 就来分享一下.
对一个新鲜事物, 我们先解决的无非就是三件事情: 是什么?为什么?怎么做?.

NDK简介

(英语:native development kit,简称NDK)是一种基于原生程序接口的软件开发工具。通过此工具开发的程序直接以本地语言运行,而非虚拟机。因此只有java等基于虚拟机运行的语言的程序才会有原生开发工具包。[维基百科]

  1. NDK是一系列工具的集合

NDK提供了一系列的工具,帮助开发者快速开发C(或C++)的动态库,并能自动将so和java应用一起打包成apk。这些工具对开发者的帮助是巨大的.

  1. NDK集成了交叉编译器,并提供了相应的mk文件隔离CPU、平台、ABI等差异,开发人员只需要简单修改mk文件(指出“哪些文件需要编译”、“编译特性要求”等),就可以创建出so。

NDK可以自动地将so和Java应用一起打包,极大地减轻了开发人员的打包工作。

那我们为什么要使用呢?

  1. 代码的保护。由于apk的java层代码很容易被反编译,而C/C++库反汇难度较大。
  2. 可以方便地使用现存的开源库。大部分现存的开源库都是用C/C++代码编写的。
  3. 提高程序的执行效率。将要求高性能的应用逻辑使用C开发,从而提高应用程序的执行效率。
  4. 便于移植。用C/C++写得库可以方便在其他的嵌入式平台上再次使用。

上述文字致谢Devin Zhang提供理论支持

是什么和为什么我就先介绍到这儿, 接下来就具体看看如何进行NDK的开发

开发前准备

开发环境

请大家务必升级到AS 2.2以上版本, 因为这个版本升级了很多内容, 详情请见 Android Studio 2.2 正式稳定版发布

  • Android Studio 2.2.2
  • JDK1.7
  • API 24
  • Gradle 2.2.2

NDK和CMake 的下载和安装

大家可以直接打开SDK进行下载和安装

SDK

由于NDK的工具包较大, 大家也可以选择从网站中下载: http://wear.techbrood.com/tools/sdk/ndk/, 选择自己对应的版本使用迅雷等工具下载即可, 不过通过这种方法一定要修改local.properties文件, 在里面添加:

//后面改成自己下载后解压的路径名
ndk.dir=C\:\\Users\\Lulu\\AppData\\Local\\Android\\android-ndk-r13

关于CMake

  1. CMakeList.txt 是脚本文件, 需要指定包含哪些源代码;
  2. 可以写一些条件语句, 实现不同的代码包含
  3. 内部说明:
    add_library 表示编译一个代码库, 内部包含了代码库的名称, 以及源代码有哪些

NDK两种开发模式

  1. ndk-build 形式; Android Studio 2.2之前的模式
  2. CMake 形式: CLion C/C++编辑器; AS2.2之后整合了CLion代码, AS就支持了CMake形式的NDK开发

开始开发

接下来通过几个案例来演示NDK的开发流程

创建工程

  1. 新建工程, 选中Include C++ Support


    Include C++ Support
  2. 一路Next之后, 在最后Finish页面尽量选中图示两项, 这样会给我们包裹一些特定的示例代码, 帮助我们理解和使用


    NDK
  3. 点击Finish, 如果出现图示错误的肯定没有好好看上面的 开发前准备


    ERROR

案例一 实现在C语言中隐藏AppKey等信息

step1: 为了使代码整洁, 咱们新建一个类 NativeHelper, 专门用于访问C语言代码的帮助类 并添加获取Appkey的方法


public class NativeHelper {
    static {
        // 加载C代码库, 库的名称, 必须是CMakeLists.txt中指定的名称
        System.loadLibrary("native-lib");
    }

    //获取C中隐藏的AppKey
    public static native String getAppKey();
}

Note: 一定要添加上面的静态代码块的内容, 否则无法加载C代码库
此时的getAppKey()方法标红, 不用管它, 继续....

step2: 在cpp目录下右击创建C/C++ Source, 选择Type, 并勾选 Create an associated hader, 为保持对应, 名字命名为: com_lulu_ndkdemo_NativeHelper, 此时会出现, 在cpp目录下会出现两个文件, 如图:

cpp

step3: 在CMakeLists.txt中的add_library中添加依关系, 点击同步

src/main/cpp/com_lulu_ndkdemo_NativeHelper.c
add_library

Note:

C代码库生成的名称规则

  1. 如果栈顶代码库名称为 "nh" 那么生成的文件必定是libnh.so
    命名规则: lib库名.so
  2. System.loadLibrary(库名); //此处不能包含前面的lib和后面的.so

step4: 在com_lulu_ndkdemo_NativeHelper.c文件中添加c语言代码

#include <jni.h>
JNIEXPORT jstring JNICALL
                  Java_com_lulu_ndkdemo_NativeHelper_getAppKey(JNIEnv *env, jclass type) {

    //测试代码, 没有任何意义
    char* app_key = "5465465416948";

    //生成 Java 中的字符串对象
    //指针的指针
    // env <=> JNINativeInterface** C语言
    return (*env)->NewStringUTF(env, app_key);
}

step5: 在MainActivity中获取AppKey, 查看结果 -> 成功


    String appKey = NativeHelper.getAppKey();
    Log.d(TAG, "onCreate: appKey => " + appKey);

Note: Java 调用C/C++代码

  1. 任何一个类的方法, 如果声明了native修饰符, 那么就可以认为是一个C代码;
  1. 可以用对象, 类直接调用
  2. 创建C/C++文件; 如果一个类中有一个native的方法, 那么对应的C方法: Java_包名类名方法名(JNIEnv *env, ...);
  3. 当Java类中包含了native的方法, 那么这个类必须写一个静态初初始化块: System.loadLibrary("库名")

案例二 实现在C语言中打印log

接下来, 只简单介绍核心代码, 不再赘述

step1: 在com_lulu_ndkdemo_NativeHelper.c中添加:


JNIEXPORT void JNICALL
Java_com_lulu_ndkdemo_NativeHelper_printLog(JNIEnv *env, jclass type, jstring str_) {
    const char *str = (*env)->GetStringUTFChars(env, str_, 0);
    //TODO: 显示Android 的日志
    // 调用Android的代码
    // 代码需要调用系统的日志库, 这个库已经在 CMakeList.txt添加了e,因此可以直接调用
    const char *tag = "NativeHelper";
    //jstring -> char*
    jboolean b = JNI_FALSE;
    const char* txt = (*env)->GetStringUTFChars(env, str_, b);
    //打印log日志
    __android_log_write(ANDROID_LOG_DEBUG, tag, txt);
    //释放string
    (*env)->ReleaseStringUTFChars(env, str_, str);
}

step2: NativeHelper中添加

//在C中打印log
public static native void printLog(String str);

step3: MainActivity中调用


//打印C语言中的Log
NativeHelper.printLog("测试Log");

完整代码

Demo已上传到github上, 欢迎大家Clone

小结

至此, 咱们应该大致了解了一下NDK开发的简单流程, 鄙人菜鸟, 希望抛砖引玉, "引"出更好的文章

本文还有下篇, 将再写一些关于NDK开发的案例Demo, 希望大家喜欢和关注

Android
Web note ad 1