Android:NDK开发流程

简介

Java程序通过JNI实现与本地C/C++代码的交互,而NDK则是Android平台上便于进行JNI开发的工具。


流程

NDK的开发流程如下:

  1. 下载NDK,设置环境变量,项目配置NDK
  2. Java文件定义native接口
  3. javah生成C/C++头文件
  4. 编写C/C++代码
  5. 编写Android.mk、Application.mk
  6. 编译出so文件
  7. 使用so文件

下面在Windows环境下逐项介绍,其他环境也基本大同小异。

1、下载NDK,设置环境变量,项目配置NDK
https://developer.android.com/ndk/downloads/index.html下载NDK并解压,拷贝解压地址如D:\android-ndk-r11b,粘贴到系统环境变量Path中;新建Android Studio工程,名为NdkDemo,打开工程设置,粘贴到NDK Location中。
设置环境变量后,如果命令行执行ndk-build无效,可以试下重启电脑。

2、Java文件定义native接口
新建一个文件src/main/com.example.ndkdemo/Foo.java,定义native接口

package com.example.ndkdemo;

public class Foo {

    public native String getString();

}

Build -> MakeProject编译一下项目生成Foo.class

3、javah生成C/C++头文件
上一步生成的Foo.class文件在app\build\intermediates\classes\debug中,使用命令行
这里写图片描述
javah class文件必须使用完整的包名,所以这里我们执行javah的地方并非在Foo.class的目录,而是在debug目录。这时候就会生成一个C/C++的头文件。
这里写图片描述

4、编写C/C++代码
新建一个文件夹app/src/jni,必须命名为jni,否则ndk找不到你的文件。拷贝上一步生成的头文件到此目录下,新建Foo.cpp

#include "com_example_ndkdemo_Foo.h"
#include  "stdio.h"

JNIEXPORT jstring JNICALL Java_com_example_ndkdemo_Foo_getString(JNIEnv *env, jobject thiz){
  return env->NewStringUTF("string from native");
}

5、编写Android.mk、Application.mk
继续在jni目录下新建Android.mk文件

LOCAL_PATH:=$(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := foo
LOCAL_SRC_FILES := Foo.cpp
include $(BUILD_SHARED_LIBRARY)

其中LOCAL_MODULE := foo表示你要编译出的so文件名,它会自动添加lib前缀以及.so后缀。LOCAL_SRC_FILES 则表示编译的文件。

默认情况下只会编译出armeabi平台下的so文件,如果想要编译出其他平台的so,则需要新建一个Application.mk文件

APP_ABI := all

上面表示编译出所有平台的so文件

6、编译出so文件
使用命令行
这里写图片描述

生成的so文件默认到同等级的libs文件夹里
这里写图片描述

7、使用so文件
将生成的so文件拷贝到src/main/jniLibs,AS默认会在这里依赖so。
代码加载so,一般哪里使用native接口,就在哪加载,所以这里是在Foo文件。

package com.example.ndkdemo;

public class Foo {

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

    public native String getString();

}

最后我们就可以使用native接口了

textView.setText(new Foo().getString());

C/C++调用Java

Java调用C/C++基本流程是,加载so,通过native接口,在JNI环境中找到相应的C/C++函数。C/C++调用Java也是相似的过程,在JNI环境中找到Java的类以及方法,然后就可以调用。

继续沿用上面的例子

1、Foo类中定义一个static方法

package com.example.ndkdemo;

public class Foo {

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

    public native String getString();

    public static void methodFromJava(String str){
        Log.i("tag", "call java from native: " + str);
    }
}

2、C/C++代码中通过JNI环境找到这个类和方法,然后即可调用。

//~ Foo.cpp
#include "com_example_ndkdemo_Foo.h"
#include  "stdio.h"
void callJavaMethod(JNIEnv *env);


JNIEXPORT jstring JNICALL Java_com_example_ndkdemo_Foo_getString(JNIEnv *env, jobject thiz){
  callJavaMethod(env); // 调用Java代码
  return env->NewStringUTF("string from native");
}

void callJavaMethod(JNIEnv *env){
    jclass clazz = env->FindClass("com/example/ndktest/Foo"); // 找到Java类

    jmethodID id = env->GetStaticMethodID(clazz,"methodFromJava","(Ljava/lang/String;)V"); // 找到该类的这个方法

    jstring str = env->NewStringUTF("hello java");
    env->CallStaticVoidMethod(clazz,id,str); // 调用这个方法
}

两点需要注意:
1. FindClass的参数写法;
2. 找方法过程有点类似Java中的反射,其中最后一个参数代表方法的签名,它的写法是(参数类型签名)返回类型签名,不同数据类型的签名有不同表示方法。比如上面的(Ljava/lang/String;)V,就代表void methodName(String str)方法的签名。


小结

如果不使用NDK,我们需要自己使用编译器将源码编译出so/dll。使用NDK,编写好Android.mk和Application.mk就能很方便地编译出不同平台的so了。通过JNI,Java程序能与本地C/C++代码交互,两者可以互调。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值