NDK开发入门(一)

本文详细介绍使用 Android Studio 2.2.2 和 NDK 进行 C/C++ 开发的过程,包括配置环境、创建项目、实现 Java 与 C/C++ 代码交互等关键步骤。

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

准备工作

工具选择

开发NDK我选择最新版的Android Studio2.2.2,主要原因是最新版已经很好的支持了c/c++的代码提示、代码调试和源代码跳转等功能,个人感觉非常好用。

开始实践

1.首先下载最新版Android studio并且下载ndk开发中需要的工具,如下图所示:

这里写图片描述
2.安装好三个工具后我们就可以进行开发了,首先我们新建一个项目,其中选中“Include C++ Support”,如下图所示:
这里写图片描述

3.创建好之后,点击“run”就可以安装运行了。

使用c/c++进行开发

创建一个Java类

public class NdkTest {


    public static native String callFromNativ(String str);

    public static native void callJavaCode(String str);

    public static native void getBitmapInfo(Bitmap bitmap);

    public static native void callJavaInstaceCode(String str);

}

public class CallFromNative {
    public static final String TAG = "CallFromNative";

    public static void showLog(String str) {
        Log.e(TAG,"callByNative = "+str);
    }

    public void showInstanceLog(String str) {
         Log.e(TAG,"callByNative = "+str);
    }

}

生成头文件

通过命令行生成头文件,首先进入到java目录下然后输入命令
这里写图片描述
然后你就可以看到生成的头文件了,打开头文件如下所示:

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

#ifndef _Included_test_com_example_liaojd_myapplication_NdkTest
#define _Included_test_com_example_liaojd_myapplication_NdkTest
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     test_com_example_liaojd_myapplication_NdkTest
 * Method:    callFromNativ
 * Signature: (Ljava/lang/String;)V
 */
JNIEXPORT void JNICALL Java_test_com_example_liaojd_myapplication_NdkTest_callFromNativ
  (JNIEnv *, jclass, jstring);

/*
 * Class:     test_com_example_liaojd_myapplication_NdkTest
 * Method:    callJavaCode
 * Signature: (Ljava/lang/String;)V
 */
JNIEXPORT void JNICALL Java_test_com_example_liaojd_myapplication_NdkTest_callJavaCode
  (JNIEnv *, jclass, jstring);
/*
 * Class:     test_com_example_liaojd_myapplication_NdkTest
 * Method:    callJavaInstaceCode
 * Signature: (Ljava/lang/String;)V
 */
JNIEXPORT void JNICALL Java_test_com_example_liaojd_myapplication_NdkTest_callJavaInstaceCode
  (JNIEnv *, jclass, jstring);

/*
 * Class:     test_com_example_liaojd_myapplication_NdkTest
 * Method:    getBitmapInfo
 * Signature: (Ljava/lang/String;)V
 */
JNIEXPORT void JNICALL Java_test_com_example_liaojd_myapplication_NdkTest_getBitmapInfo
  (JNIEnv *, jclass, jobject);

#ifdef __cplusplus
}
#endif
#endif

实现函数声明

在cpp文件夹下面创建一个main.c的文件,如下所示:

//
// Created by liaojd on 2017/1/13.
//
#include <android/bitmap.h>
#include "jni.h"
#include "android/log.h"
#include "android/bitmap.h"

#define  TAG    "NDK_TEST"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG,  __VA_ARGS__)

/**
 * 实现打印输出并返回一个字符串
 */
JNIEXPORT jstring JNICALL Java_test_com_example_liaojd_myapplication_NdkTest_callFromNativ
        (JNIEnv *env, jclass obj, jstring jstr) {
    LOGD("test ndk");
    return (*env)->NewStringUTF(env,"Test NDK");
}


/**
 *回调Java静态方法
 */
JNIEXPORT void JNICALL Java_test_com_example_liaojd_myapplication_NdkTest_callJavaCode
        (JNIEnv *env, jclass thiz, jstring jstr) {
    //得到类的实例对象
    jclass clazz = (*env)->FindClass(env,"test/com/example/liaojd/myapplication/CallFromNative");

    jmethodID showLog= (*env)->GetStaticMethodID(env, clazz, "showLog","(Ljava/lang/String;)V");
    //调用java函数
    jstring str =(*env)->NewStringUTF(env, "Hi,I'm From C");
    (*env)->CallStaticVoidMethod(env,clazz,showLog,str);
}

/**
 * 回调Java实例方法
 */
JNIEXPORT void JNICALL Java_test_com_example_liaojd_myapplication_NdkTest_callJavaInstaceCode
        (JNIEnv *env, jclass thiz, jstring jstr) {
    //得到类的实例对象
    jclass clazz = (*env)->FindClass(env,"test/com/example/liaojd/myapplication/CallFromNative");

    jmethodID showInstanceLog= (*env)->GetMethodID(env, clazz, "showInstanceLog","(Ljava/lang/String;)V");
    //得到一个实例对象
    jobject instance = (*env)->AllocObject(env,clazz);
    //调用java函数
    jstring  str =(*env)->NewStringUTF(env, "Hi,I'm From C");
    (*env)->CallVoidMethod(env,instance,showInstanceLog,str);
}

/**
 * 获取图片信息
 */
JNIEXPORT void JNICALL Java_test_com_example_liaojd_myapplication_NdkTest_getBitmapInfo
        (JNIEnv *env, jclass obj, jobject jbitmap) {
    AndroidBitmapInfo info;
    AndroidBitmap_getInfo(env,jbitmap,&info);
    LOGD("bitmap width = %d height = %d", info.width, info.height);
}

上面的例子中获取方法的ID的时候需要传入方法描述符,在Java中它表示方法的签名,Java类型签名映射表如下:

Java类型签名
BooleanZ
ByteB
CharC
ShortS
IntI
LongJ
FloatF
DoubleD
fully-qualified-classLfully-qualified-clas;
type[][type
method type(arg-type)ret-type

用类型签名映射手工生成的方法描述符是一件非常繁琐的任务,不一定每次都记住,所以JDK为我们提供了javap反汇编命令行程序,如下所示:
这里写图片描述

加载动态库

    static {
        System.loadLibrary("native-lib");
    }

添加运行的代码

  NdkTest.callFromNativ("callFromNativ");
  NdkTest.callJavaCode("callJavaCode");
  NdkTest.callJavaInstaceCode("callInstanceCode");
  NdkTest.getBitmapInfo(bitmapDrawable.getBitmap());

因为bitmap.h在libjnigraphics.so中,所以修改CMakeLists.txt文件,如下所示:

# Sets the minimum version of CMake required to build the native
# library. You should either keep the default value or only pass a
# value of 3.4.0 or lower.

cmake_minimum_required(VERSION 3.4.1)

# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds it for you.
# Gradle automatically packages shared libraries with your APK.

add_library( # Sets the name of the library.
             native-lib

             # Sets the library as a shared library.
             SHARED

             # Provides a relative path to your source file(s).
             # Associated headers in the same location as their source
             # file are automatically included.
             src/main/cpp/main.c)

# Searches for a specified prebuilt library and stores the path as a
# variable. Because system libraries are included in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.

find_library( # Sets the name of the path variable.
              log-lib

              # Specifies the name of the NDK library that
              # you want CMake to locate.
              log )

find_library( # Sets the name of the path variable.
              jnigraphics-lib

              # Specifies the name of the NDK library that
              # you want CMake to locate.
              jnigraphics )

# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in the
# build script, prebuilt third-party libraries, or system libraries.

target_link_libraries( # Specifies the target library.
                       native-lib

                       # Links the target library to the log library
                       # included in the NDK.
                       ${jnigraphics-lib}
                       ${log-lib} )

涉及到相关的知识点

1.Cmake参考资料
cmake document
2.最新版Android studio关于如何使用c/c++请参考官方文档
官方使用教程

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值