Android JNI 编译so库

本文详细介绍如何使用Android NDK进行开发,包括环境搭建、C/C++编译so库的具体步骤,以及通过示例项目演示如何创建并调用JNI方法。

环境

  • Android Studio 3.0
  • JDK 1.8
  • Gradle 4.1

Demo地址:

https://github.com/seeways/NDKDemo

C++编译so库

http://blog.csdn.net/lftaoyuan/article/details/78645814

C编译so库

创建项目

C++编译so库中已经有了创建后的示例,不多赘述。

建立MyJNI类

package com.test.ndkdemo;

/**
 * Created by TaoYuan on 2017/11/24 0024.
 */

public class MyJNI {
    //调用so库声明
    static {
        System.loadLibrary("MyJNI");
    }

    /**
     * 调用so库方法
     */
    //输出字符串
    public native String sayHello();

    //输出 x+y 计算结果
    public native int sum(int x, int y);

    //接收byte数组,输出json信息
    public native String receiveYUV(byte[] bytes);

}

然后make project,这是在C++同一个项目下生成的,所以先忽略cmake生成的文件,

设置快速工具,当然也可以直接用命令,如果不怕麻烦的话

设置javah

设置ndk-build

  • javah

    • Program:
      $JDKPath$\bin\javah.exe
    • Parameters:
      -classpath . -jni -d $ModuleFileDir$\src\main\jni $FileClass$
    • Working directory: $ModuleFileDir$\src\main\Java
  • ndk-build

    • Program:
      你的ndk地址\ndk-build.cmd
    • Working directory: $ProjectFileDir$\app\src\main

生成后,会出现jni文件夹,里面有根据MyJNI生成的头文件,然后新建C文件就可以写C代码了

可以考虑直接把头文件里的方法名直接复制过来,然后编写逻辑

//
// Created by TaoYuan on 2017/11/24 0024.
//

#include "com_test_ndkdemo_MyJNI.h"

JNIEXPORT jstring JNICALL Java_com_cyyz_ndkdemo_MyJNI_sayHello(JNIEnv *env, jobject instance){

    return (*env)->NewStringUTF(env,"say 就 say!\n Hello");

}


JNIEXPORT jint JNICALL Java_com_cyyz_ndkdemo_MyJNI_sum(JNIEnv *env, jobject instance, jint x, jint y){
    return x + y;
}

JNIEXPORT jstring JNICALL
Java_com_test_ndkdemo_MyJNI_receiveYUV(JNIEnv *env, jobject instance, jbyteArray bytes_) {
    jbyte *bytes = (*env)->GetByteArrayElements(env, bytes_, NULL);
    if (bytes == NULL) {
        return 0; /* exception occurred */
    }

    //do something...

    char *say = "输出的json数据";
    (*env)->ReleaseByteArrayElements(env, bytes_, bytes, 0);
    return (*env)->NewStringUTF(env, say);
}

配置gradle

modules build.gradle

  • moduleName:so名称
  • abiFilters:cpu架构
  • ldLibs:连接库
  • cFlags:编译选项,C++里是cppFlags
  • stl: C++运行库
    ndk{
        moduleName "MyJNI"
        abiFilters "armeabi","armeabi-v7a"
    }

生成makefile

  1. make project
  2. ${ProjectPath}\app\build\intermediates\ndk下会生成Android.mk
  3. copy到jni文件夹下
  4. 用刚才配置的ndk-build构建Android.mk
  5. finish
    finish
### 使用JNIAndroid中生成或使用.so 为了使应用程序能够调用本地方法,在`app/src/main/jniLibs/`目录下放置`.so`文件是一个常见做法[^1]。当涉及到创建这些共享时,开发者通常会编写C/C++代码并利用NDK构建工具链来编译它们。 对于希望集成现有原生代码的情况,可以按照如下方式操作: #### 准备工作环境 确保已安装Android NDK,并配置好开发环境中相应的路径变量以便于命令行工具访问。 #### 编写C/C++源码 定义想要暴露给Java层的方法接口,例如在一个名为`native-lib.cpp`的文件里实现逻辑功能。 ```cpp #include <jni.h> #include <string> extern "C" JNIEXPORT jstring JNICALL Java_com_example_myapplication_MainActivity_stringFromJNI(JNIEnv *env, jobject /* this */) { std::string hello = "Hello from C++"; return env->NewStringUTF(hello.c_str()); } ``` 此段代码展示了如何声明一个简单的函数用于返回字符串至Java端。 #### 构建脚本设置(CMakeLists.txt 或 Android.mk) 如果采用CMake作为构建系统,则需编辑项目中的`CMakeLists.txt`文件以指定输入源文件以及链接必要的静态,像这样: ```cmake add_library(native-lib SHARED src/main/cpp/native-lib.cpp) find_library(log-lib log) target_link_libraries(native-lib ${log-lib}) ``` 上述片段说明了怎样添加一个新的共享(`SHARED`)目标,并将其与日志记录器连接起来。 另外一种情况是基于`ndk-build`体系结构下的`Android.mk`文件可能看起来像是这样的: ```makefile LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := app-glue LOCAL_SRC_FILES := ${ANDROID_NDK}/sources/android/native_app_glue/android_native_app_glue.c include $(BUILD_STATIC_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE := native-lib LOCAL_SRC_FILES := src/main/cpp/native-lib.cpp LOCAL_STATIC_LIBRARIES := app-glue LOCAL_LDLIBS += -llog include $(BUILD_SHARED_LIBRARY) ``` 这里不仅包含了自定义模块还加入了来自NDK自带的支持包(如`android_native_app_glue`),并且指定了要链接的日志。 #### 加载SO并在Java侧调用 最后一步是在应用启动期间加载所需的动态链接,这可以通过修改活动类(比如`MainActivity.java`)完成初始化过程: ```java static{ System.loadLibrary("native-lib"); } public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); TextView tv = findViewById(R.id.sample_text); tv.setText(stringFromJNI()); // 调用了由C++实现的方法 } public native String stringFromJNI(); } ``` 这段Java代码实现了对之前提到过的本地方法的实际调用,并将结果显示到界面上。 通过以上步骤就可以成功地在Android平台上运用JNI技术来生成和使用`.so`形式的原生了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值