Skip to content

Latest commit

 

History

History
150 lines (103 loc) · 5.28 KB

README.md

File metadata and controls

150 lines (103 loc) · 5.28 KB

layout: post title: Android NDK 的简单使用 category: Android tags: [Android, NDK] keywords: description:

概念准备

为了完成标题,先看几个概念:

  • JNI: Java Native Interface,Java提供,用来实现Java和C的互相调用,但是使Java丧失了跨平台的特性.
  • NDK: Native Development Kit,Android提供,基于JNI,跨平台.
  • 编译: CPU最常见的即ARM和x86,交叉编译就是在一个平台上编译出另一个平台可用的代码, NDK就是交叉编译工具.
  • 为何使用NDK,抄过来以下几点:
    • 方便跨平台.
    • 算法复杂或资源消耗大的模块.
    • 可以避免核心代码被反编译.

工具准备

下面主要讲如何在MAC OS X 上使用NDK

  • 安装AndroidStudio.
  • 安装NDK,官网下载,解压chmod a+x xx.bin ./xx.bin

开始

  1. 新建一个空白工程,具体内容请参考:Building Your First App

  2. 使用Project视图,在项目主目录右键新建一个名为method的模块, New - Module - Android Library - Add No Activity - Finish.

  3. 在app模块的MainActivity.java添加native方法

     public class MainActivity extends AppCompatActivity {
         public native int add(int a, int b);
    

    此处的add对应后面c文件中的方法(注意对象类型查看末尾链接)和h头文件的自动生成.

  4. 生成头文件

    method模块根目录新建一个autojavah.sh用来生成.h头文件 :

     #!/usr/bin/env bash
     export ProjectPath=$(cd "../$(dirname "$1")"; pwd)
     export TargetClassName="com.yanze.ajnidemo.MainActivity"
    
     export SourceFile="${ProjectPath}/app/src/main/java"
     export TargetPath="${ProjectPath}/method/src/main/jni"
    
     cd "${SourceFile}"
     javah -d ${TargetPath} -classpath "${SourceFile}" "${TargetClassName}"
     echo -d ${TargetPath} -classpath "${SourceFile}" "${TargetClassName}"
    

    前四行定义,后两行执行,最后echo一下,照着自己改,注意一下TargetPath这个. 创建完成后会提示安装Bash Plugin,安装后重启AS,右键Run(或者去目录自己运行).

    生成的.h头文件:

     /* DO NOT EDIT THIS FILE - it is machine generated */
     #include <jni.h>
     /* Header for class com_yanze_ajnidemo_MainActivity */
    
     #ifndef _Included_com_yanze_ajnidemo_MainActivity
     #define _Included_com_yanze_ajnidemo_MainActivity
     #ifdef __cplusplus
     extern "C" {
     #endif
     /*
     * Class:     com_yanze_ajnidemo_MainActivity
     * Method:    add
     * Signature: (II)I
     */
     JNIEXPORT jint JNICALL Java_com_yanze_ajnidemo_MainActivity_add
     (JNIEnv *, jobject, jint, jint);
    
     #ifdef __cplusplus
     }
     #endif
     #endif
    

    根据app模块MainActivity.java中的add方法对应生成了一个add方法.注意对象类型(jint)和命名规则.

  5. add.c文件:

     // Created by Kyle on 15/11/19.
     #include "com_yanze_ajnidemo_MainActivity.h" 
     #include <stdio.h>
    
     JNIEXPORT jint JNICALL Java_com_yanze_ajnidemo_MainActivity_add(JNIEnv * env,jobject thiz, jint a, jint b){
     int c = a + b;
     return c;
     }
    

    注意c++和c写法略有不同.

  6. 编译

    1. 配置NDK环境,在根目录"local.properties"文件末尾添加NDK的目录,我的是: ndk.dir=/Users/kyle/workspace/ndk/android-ndk-r10e

    2. 在"method"模块下的"gradle.properties"末尾添加android.useDeprecatedNdk=true.

    3. 编译:右键method模块,make module,成功后会生成 libmethod.so(/Ajnidemo/method/build/intermediates/ndk/release/lib/各平台/libmethod.so)Android.mk(/Ajnidemo/method/build/intermediates/ndk/release/Android.mk)两个文件.

      libmethod.so引用时名字是"method",Android.mk决定了编译时的配置(详细说明见引用链接).

    4. 给app模块添加method依赖.右键app模块 - Open Module Setting - Dependencies - + - Module Dependency - method.

  7. 加载库文件.app模块的MainActivity类下:

     static{
         System.loadLibrary("method");
     }
    

    调用add方法(第二行和第三行),写在onCreate下,以便启动时显示.

     TextView tv = new TextView(this);
     MainActivity t = new MainActivity();
     int c = t.add(1024,233);
     String s = Integer.toString(c);
     tv.setText(s);
     setContentView(tv);
    

    嗯,最后是丑陋不堪的效果图:

    效果图

相关链接

虽然工具不同,方式不一,蛋整体的思路是一样的,具体操作可以参照第二个链接,不同的地方主要是上面第6条,另外NDK的Samples目录下也有一下Sample.