Android NDK/JNI初探

NDK, native sdk, 通过JNI访问,JNI是Java Native Interface的缩写,通过使用 Java本地接口书写程序,可以确保代码在不同的平台上方便移植。从Java1.1开始,JNI标准成为java平台的一部分,它允许Java代码和其他语言写的代码进行交互。JNI一开始是为了本地已编译语言,尤其是C和C++而设计的,
通过它可以扩展很多系统底层的能力,如opencv,openGL,ffmpg,以及通过将隐私代码如加密算法打包,并进行混淆,大大增加了破解难度,提供程序的安全性.

新建工程

├── androidTest
│   └── java
│       └── com
├── main
│   ├── AndroidManifest.xml
│   ├── cpp                 // 源代码目录
│   │   ├── CMakeLists.txt 
│   │   └── native-lib.cpp
│   ├── java
│   │   └── com
│   └── res ..
└── test
    └── java
        └── com

cpp文件示例

#include <jni.h>
#include <string>

extern "C" JNIEXPORT jstring JNICALL 
Java_com_example_myapplication_MainActivity_stringFromJNI(  // Java_{packagename siplt with _}{CallerClassName}_{MethodNameInCaller}
        JNIEnv* env,
        jobject /* this */) {
    std::string hello = "Hello from C++";


    return env->NewStringUTF(hello.c_str());
}

android docs中有提到除了通过dlsym的方式查找外,还可在利用JNI_OnLoad中显示的注册native方法.JNI_OnLoad是在.so库加载之后,两者比较在JNI_OnLoad中注册开销更小,它是懒加载的.

Note: JavaVM是Java虚拟机在JNI层的接口,它封装一些JVM操 区别: JavaVM 全局只有一个,JNIEnv 每个线程都有一个,所以千万不要夸线程直接饮用JNIEnv,可以通过JavaVM暴露的GetINIEnv`来获取.

CMakeList.txt示例

依赖cmake,跨平台安装构建工具,它封装了多种编译的命令,提供一种可以使用target来描述的方式来设置工程的构建行为,使得工程编译配置和依赖选项比使用原始的命令更加清晰

//cmake的最低支持版本
cmake_minimum_required(VERSION 3.10.2)
project("myapplication")

add_library( # Sets the name of the library.
        myapplication //二进制库的名字,使用前通过`System.loadLibrary("myapplication")`加载,这两处名字必须一致

        # Sets the library as a shared library. 库的类型, 也可以是`STATIC`
        SHARED

        # Provides a relative path to your source file(s).
        native-lib.cpp)

//查找并设置,log库的路径变量 log-lib
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)

//将 log-lib链接到target中
target_link_libraries( # Specifies the target library.
        myapplication

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

命令非常多,但基本都围绕以下几个部分来设置

  1. 需要编译的源码位置描述
  2. 头文件搜索路径描述
  3. 预编译宏命令
  4. 依赖链接
  5. 编译时的link选项
  6. 编译时的功能选项,通常和语言特性有关,如-std设置

更多工程配置格式可以参考这个文档 https://cmake.org/cmake/help/latest/guide/tutorial/index.html

在主工程中使用

在使用的主工程的app目录下添加cmake的依赖

    externalNativeBuild {
        cmake {
            path file('src/main/cpp/CMakeLists.txt')
            version '3.10.2'
        }
    }
- 在调用内`MainActivity`中声明这个方法是一个外部方法,需要加载外部库追后才能访问到

external fun stringFromJNI(): String


```kotlin
class MainActivity : AppCompatActivity() {
    companion object {
        // Used to load the 'myapplication' library on application startup.
        init {
            System.loadLibrary("myapplication1")
        }
    }

调用此方法

  binding.sampleText.text = stringFromJNI()

so文件获取

首先解码apk,apkTool d -fs app-debug.apk
lib文件默认在apklib目录

jiodg45@jiodg45s-MacBook-Pro app-debug % cd lib 
jiodg45@jiodg45s-MacBook-Pro lib % tree -L 2
.
└── x86_64
    └── libmyapplication.so

实际开发需要将 so文件和JNI接口实现进行从新整合,封装成java简单易用的方法,整个流程并不复杂,重点还是要熟悉底层代码的开发

参考以下几篇文章

https://docs.oracle.com/javase/6/docs/technotes/guides/jni/spec/design.html#wp16696
https://developer.android.google.cn/training/articles/perf-jni
http://gityuan.com/2016/05/28/android-jni/
https://github.com/obfuscator-llvm/obfuscator

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值