【NDK开发】基础环境搭建

Security Classification: 【C-1】 | Publish Time:2024-09-26 | Category:Coding | Edit

Expiry Notice: The article was published three months ago. Please independently assess the validity of the technical methods and code mentioned within. :)

AI Summary: 本文介绍了在Android Studio中使用JNI和NDK进行C/C++代码的实现与Java层的交互。首先说明了环境安装及前置知识,接着详细解释了CMakeLists文件的结构,定义了项目名称和要编译的源文件。接下来,展示了MainActivity.java的代码,定义了两个native方法并在onCreate中调用xxjni()。然后,提供了native_depy.cpp的实现,使用JNIEnv和JNI数据类型将C++字符串返回给Java层。最后,介绍了编译过程和获取生成的APK及.so文件的步骤。 --- (From Model:gpt-4o-mini-2024-07-18)

环境安装

官网Android Studio一把梭,务必使用非中国大陆代理后下载dl.google.com上的一些依赖,不然你会痛苦。

前置知识

此前研究过webview和java层进行通信的方式,在美团这个叫做knb。与之类似更底层的就是JNI,NDK工具使咱们能够在 Android 应用中使用 C 和 C++ 代码,它提供了众多平台库,我们可使用这些平台库管理原生 activity 和访问实体设备组件,例如传感器和触控输入。

为了应用的安全性,会将一些复杂的逻辑和算法通过本地代码(C或C++)来实现,然后打包成.so动态库文件,并提供 Java 接口供应用层调用,这么做的目的主要就是为了提供应用的安全性,防止被反编译后被不法分子分析应用的逻辑。

基础文件目录

Cmake.list

第一行指定所需的 CMake 最低版本。
第二行设置项目名称为 “a**“。
第三行添加一个名为 ${CMAKE_PROJECT_NAME} 的共享库,并将源文件 native-lib.cpp 和 native_depy.cpp 添加到该库中。这些源文件将被编译为共享库。
第四行指定链接到 ${CMAKE_PROJECT_NAME} 库的其他库。在这里,${CMAKE_PROJECT_NAME} 库将链接到 Android NDK 提供的 android 库和 log 库。这样编译生成的libaa会引用包含android和log两个库。

com/example/a2023110803/MainActivity.java

  1. package com.example.a2023110803;
  2. import androidx.appcompat.app.AppCompatActivity;
  3. import android.os.Bundle;
  4. import android.widget.TextView;
  5. import com.example.a2023110803.databinding.ActivityMainBinding;
  6. public class MainActivity extends AppCompatActivity {
  7. static {
  8. System.loadLibrary("aa");
  9. }
  10. private ActivityMainBinding binding;
  11. @Override
  12. protected void onCreate(Bundle savedInstanceState) {
  13. super.onCreate(savedInstanceState);
  14. binding = ActivityMainBinding.inflate(getLayoutInflater());
  15. setContentView(binding.getRoot());
  16. TextView tv = binding.sampleText;
  17. tv.setText(xxjni());
  18. }
  19. public native String xxjni();
  20. public native String testJNI();
  21. }

代码中定义两个native函数,xxjni()和testjni()。我们可以通过jni调用这两个方法。
在onCreate的最后两行,我们调用了xxjni()方法,并通过TextView的setText方法把返回值设置在屏幕上。

native_depy.cpp

在cmake.list中我们定义了一个共享库,会把native_depy.cpp和另一个cpp文件添加到库中。java代码最终调用时,也是调用cpp里定义的函数。

代码如下:

  1. #include <jni.h>
  2. #include <string>
  3. extern "C" jstring
  4. Java_com_example_a2023110803_MainActivity_xxjni(JNIEnv *env,jobject) {
  5. std::string hello = "a222nother";
  6. return env->NewStringUTF(hello.c_str());
  7. }

在这个声明函数的代码中,使用了 extern “C” 关键字。这是因为 C++ 支持函数重载,而 Java 不支持函数重载。为了能够在 C++ 中定义一个可以被 Java 调用的函数,需要使用 extern “C” 来告诉编译器按照 C 语言的规则进行函数命名和调用约定。

通过jstring这个JNI 中的数据类型,表示一个 Java 字符串。

函数声明做了静态绑定,需要java+包名+函数名的方式,同时默认带有两个参数。JNIEnv 是一个指向 JNI 环境的指针,jobject 是一个代表调用该函数的 Java 对象的指针。方便c++从java层调用方法或者获取数据。

std::string hello = “a222nother”;: 在 C++ 中创建一个字符串变量 hello,并赋值为 “a222nother”。
return env->NewStringUTF(hello.c_str());: 使用 JNI 环境的 NewStringUTF 函数将 C++ 字符串转换为 Java 字符串,并返回给 Java 端。

编译测试

设置过滤,只编译arm64。(删除会编译多个平台libso,但是目前够用)
点击build->rebuild project ,在outputs ->debug目录下得到一个apk。

解压后就能看到编译好的so文件了。


Comment List

© Copyright: This article is an original work and the copyright belongs to the  Depy's docs  unless marked as Reproduced

Please contact the blogger for authorization to reprint