【NDK开发】基础环境搭建 密级: 【C-1】 | 时间:2023-11-08 | 目录:编程开发 | 编辑本文 文章距今已发表三个月,请自行判断文中技术方法、代码的有效性:) ## 环境安装 官网Android Studio一把梭,务必使用非中国大陆代理后下载dl.google.com上的一些依赖,不然你会痛苦。 ## 前置知识 此前研究过webview和java层进行通信的方式,在美团这个叫做knb。与之类似更底层的就是JNI,NDK工具使咱们能够在 Android 应用中使用 C 和 C++ 代码,它提供了众多平台库,我们可使用这些平台库管理原生 activity 和访问实体设备组件,例如传感器和触控输入。 为了应用的安全性,会将一些复杂的逻辑和算法通过本地代码(C或C++)来实现,然后打包成.so动态库文件,并提供 Java 接口供应用层调用,这么做的目的主要就是为了提供应用的安全性,防止被反编译后被不法分子分析应用的逻辑。 ## 基础文件目录 ### Cmake.list ![](https://p0.meituan.net/xianfu/4776ecd2dda9446aa1f21fbc397efca465724.png%40watermark=1&&object=L3dkY2Zsb3cvN2RiN2M4NTFjYmVjZDg4MTM1OTZjMTYzOWE2MzQ4MDM0MjY0LnBuZw==&p=8&t=90&x=10&y=10) 第一行指定所需的 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 ```java package com.example.a2023110803; import androidx.appcompat.app.AppCompatActivity; import android.os.Bundle; import android.widget.TextView; import com.example.a2023110803.databinding.ActivityMainBinding; public class MainActivity extends AppCompatActivity { static { System.loadLibrary("aa"); } private ActivityMainBinding binding; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); binding = ActivityMainBinding.inflate(getLayoutInflater()); setContentView(binding.getRoot()); TextView tv = binding.sampleText; tv.setText(xxjni()); } public native String xxjni(); public native String testJNI(); } ``` 代码中定义两个native函数,xxjni()和testjni()。我们可以通过jni调用这两个方法。 在onCreate的最后两行,我们调用了xxjni()方法,并通过TextView的setText方法把返回值设置在屏幕上。 ### native_depy.cpp 在cmake.list中我们定义了一个共享库,会把native_depy.cpp和另一个cpp文件添加到库中。java代码最终调用时,也是调用cpp里定义的函数。 代码如下: ```cpp #include #include extern "C" jstring Java_com_example_a2023110803_MainActivity_xxjni(JNIEnv *env,jobject) { std::string hello = "a222nother"; return env->NewStringUTF(hello.c_str()); } ``` 在这个声明函数的代码中,使用了 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 端。 ## 编译测试 ![](https://p0.meituan.net/xianfu/6a2529dfbdd601580b3ed35b34997c2269860.png%40watermark=1&&object=L3dkY2Zsb3cvN2RiN2M4NTFjYmVjZDg4MTM1OTZjMTYzOWE2MzQ4MDM0MjY0LnBuZw==&p=8&t=90&x=10&y=10) 设置过滤,只编译arm64。(删除会编译多个平台libso,但是目前够用) 点击build->rebuild project ,在outputs ->debug目录下得到一个apk。 ![](https://p0.meituan.net/xianfu/97dc161e82cff23a5690622ebfe8b121114047.png%40watermark=1&&object=L3dkY2Zsb3cvN2RiN2M4NTFjYmVjZDg4MTM1OTZjMTYzOWE2MzQ4MDM0MjY0LnBuZw==&p=8&t=90&x=10&y=10) 解压后就能看到编译好的so文件了。 评论列表 写评论 您的IP:18.117.8.175,临时用户名:df57219e评论已接入DepyWAF审计与流量系统,请勿频繁操作导致IP拉黑 提交评论 © 版权声明:非标注『转载』情况下本文为原创文章,版权归 Depy's docs 所有,转载请联系博主获得授权。