Android NDK开发

本文介绍如何使用JNI和NDK在Android项目中集成C/C++代码。从创建项目到生成.so库,涵盖布局文件配置、JNI目录搭建、C/C++代码编写及与Java层交互等关键步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

NDK


JNI

JNI,是Java Native Interface的缩写,则Java本地调用,JNI可以做到:

  • Java程序中的函数可以调用Native语言写的函数,Native一般指的是C/C++编写的函数。
  • Native程序中的函数可以调用Java层的函数,也就是在C/C++程序中可以调用Java的函数。

在Android中,对于一些需要高效率的执行操作(例如算法、文件读取),最好需要采用C/C++编码,因为C/C++是一门高效率的语言。


Demo

创建Android项目

布局文件:activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/id_textview"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!" />
</RelativeLayout>

创建JNI目录

右键 app module —New—Folder—JNI Folder,在app下会建立一个jni的目录,该jni目录和java目录是处在同一层次。

项目结构


新建JNI相关的类

例如 JNIClass ,其中的 native 关键词表明这个方法是本地native的方法

public class JNIClass {
    public native String getContent();
}

生成 JNIClass 的头文件.h

用终端(Linux)或cmd(Windows),cd 到我们项目 YOUR_PROJECT_NAME/app/src/main/java 路径下:

javah -jni com.yao.jnidemo.JNIClass

注意:

  • 注意cd到的目录,因为查找类名需要根据包名查找,所以需要cd到包名路径的上一层目录(也就是以上目录)
  • 将以上com.yao.jnidemo 换为你自己的包名,JNIClass 换为你自己创建的类名
  • 类名 JNIClass 不需要加 .java 后缀
  • 切勿将命令写成:javah -jni com/yao/jnidemo/JNIClass,否则会出现:Exception in thread "main" java.lang.IllegalArgumentException: Not a valid class name: com/yao/jnidemo/JNIClass.java 的问题

生成的头文件内容如下:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_yao_jnidemo_JNIClass */

#ifndef _Included_com_yao_jnidemo_JNIClass
#define _Included_com_yao_jnidemo_JNIClass
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_yao_jnidemo_JNIClass
 * Method:    getContent
 * Signature: ()Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_com_yao_jnidemo_JNIClass_getContent
  (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif

头文件中包含了一个函数,返回类型为 jstring ,函数名为 Java_com_yao_jnidemo_JNIClass_getContent ,我们需要在源文件 .c 中实现该函数。


移动头文件

执行上一步操作之后,在以上 YOUR_PROJECT_NAME/app/src/main/java 下就会生成一个 com_yao_jnidemo_JNIClass.h 的头文件,将该头文件剪切到我们创建的jni文件夹


创建C/C++代码

在 jni目录下,新建一个 source_file.c 的文件,实现上面提到的函数,代码如下:

#include "com_yao_jnidemo_JNIClass.h"

JNIEXPORT jstring JNICALL Java_com_yao_jnidemo_JNIClass_getContent
        (JNIEnv *env, jobject obj){
    return (*env)->NewStringUTF(env,"Hello JNI!");
}

修改 appbuild.gradle

defaultConfig 中添加:

ndk{
            moduleName "jniso"          //生成的so名字
            abiFilters "armeabi", "armeabi-v7a", "x86"  //输出指定三种abi体系结构下的so库
        }

再次修改 JNIClass.java

加载生成的库 .so 文件

public class JNIClass {

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

    public native String getContent();
}

设置NDK路径

  1. File — Project Structure — SDK Location — Android NDK Location
  2. 或者可以在 local.properties 中指定路径:,例如
sdk.dir=/home/yao/Android/Sdk
ndk.dir=/home/yao/Android/Ndk

修改 gradle.properties

添加 android.useDeprecatedNdk=true ,否则可能会出现以下问题:

Error:(14, 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.


MainActivity.java

public class MainActivity extends AppCompatActivity {

    private TextView mTextView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mTextView = (TextView) findViewById(R.id.id_textview);
        mTextView.setText(new JNIClass().getContent());
    }
}

通过获取一个 JNIClass 的对象,调用本地native的 getContent 方法,在 mTextView 中显示。


生成.so库

app/build/intermediates/ndk/debug/lib 目录下有三个文件夹: armeabi,armeabi-v7a,x86,对应三种不同abi,而每个文件夹下都有生成的 .so 文件:libjniso.so


其他问题

有的人出现了以下问题:

Error:Execution failed for task ‘:app:compileDebugNdk’.
com.android.ide.common.process.ProcessException: org.gradle.process.internal.ExecException: Process ‘command ‘D:\Android\android-ndk-r9d\ndk-build.cmd” finished with non-zero exit value 2

在我的项目并没有出现,但我觉得解决以上该问题:

  • 首先确认jni目录所处的路径是否有错
  • 重新下载、替换NDK
  • 在jni目录下新建一个空的源文件,例如 empty.c

谢谢

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值