Android jni引用第三方so动态库和.a静态库并且调用(c)方法

news2024/11/28 15:50:56

最近花了一周时间来入门学习 Android JNI方面的知识,因为后续的工作很多需要用到c c++库,我需要用jni来包装一下c函数,来提供给上次java调用。总之多学点知识对自己有好处。

案例效果:
在这里插入图片描述
上文我们讲解了
android studio cmake生成.a文件(静态库)及调用(c c++)静态库.a

本文接着上文,这次我们利用JNI 来引用第三方动态库so文件,并且让Java调用它的函数。

第一步:生成.so动态库文件

编写C文件和头文件

DynamicLibraryTest.h

//
// Created by Administrator on 2023/9/5/005.
//

#ifndef ANDROIDCMAKE_DYNAMICLIBRARYTEST_H
#define ANDROIDCMAKE_DYNAMICLIBRARYTEST_H

#endif //ANDROIDCMAKE_DYNAMICLIBRARYTEST_H

int dynamicAdd(int a,int b,int c);

char * getDynamicName(char * firstName,char * lastName);

DynaminLibraryTest.cpp

//
// Created by Administrator on 2023/9/5/005.
//

#include "../include/static/DynamicLibraryTest.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int dynamicAdd(int a,int b,int c){
    return a+b+c;
}

char * getDynamicName(char * firstName,char * lastName){
    char *name = (char *) malloc(strlen(firstName) + strlen(lastName));
    strcpy(name, firstName); // 把firstName复制到name中
    strcat(name, lastName); // 把lastName追加到name中
    return name;
}

编写CmakeLists文件

    add_library(${CMAKE_PROJECT_NAME} SHARED   
        src/DynaminLibraryTest.cpp   
        )

make project之后,生成了.so动态库文件。
在这里插入图片描述

生成动态库之后,我把文件复制到了jni目录下面.
在这里插入图片描述

第二步:JNI动态注册.so动态库中的函数

编写cmakeList文件


cmake_minimum_required(VERSION 3.22.1)

project("cmake")

add_library(${CMAKE_PROJECT_NAME} SHARED
            native-lib.cpp
            src/libtest.c
            # 编写动态库用到的文件,已经生成了deynaminLibraryTest.so文件就注释掉这个代码
#        src/DynaminLibraryTest.cpp   
        )

#导入已经编译好的第三方静态库 或者 动态库  本例导入的静态库
add_library(calStatic STATIC IMPORTED)
#设置静态库(.a)导入的路径
set_target_properties(calStatic PROPERTIES IMPORTED_LOCATION
        ${CMAKE_CURRENT_SOURCE_DIR}/jni/${CMAKE_ANDROID_ARCH_ABI}/libcalStatic.a
)

#添加第三方 动态库
add_library(dynamicLibraryTest SHARED IMPORTED)
#设置动态库(.so)导入的路径
set_target_properties(dynamicLibraryTest PROPERTIES IMPORTED_LOCATION
        ${CMAKE_CURRENT_SOURCE_DIR}/jni/${CMAKE_ANDROID_ARCH_ABI}/libdynamicLibraryTest.so)

#通过target_link_libraries命令指明库文件,且通过target_include_directories命令指明相应的库头文件
target_include_directories(${CMAKE_PROJECT_NAME} PUBLIC ${PROJECT_SOURCE_DIR}/include/static/)
#需要链接或者编译的库
target_link_libraries(${CMAKE_PROJECT_NAME}
        # List libraries link to the target library
        android
        # 第三方静态库。
        calStatic
        # 第三方动态库
        dynamicLibraryTest
        log)

JNI动态注册函数

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

#include "libtest.h"//内部头文件,cmake需要连接源文件地址
#include "CalculStatic.h"//第三方静态库 .a
#include "DynamicLibraryTest.h"//第三方动态库 .so

#include <android/log.h>
#define LOG_TAG "YIQI"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)

//静态注册和动态注册,函数名一样的时候,优先用动态注册的,动态注册效率高。
//静态注册
//extern "C" JNIEXPORT jstring JNICALL
//Java_com_gitbaike_cmake_MainActivity_stringFromJNI(
//        JNIEnv* env,
//        jobject /* this */) {
//    std::string hello = "Hello from C++ 静态注册";
//    return env->NewStringUTF(hello.c_str());
//}

//静态注册
extern "C" JNIEXPORT void JNICALL
Java_com_gitbaike_cmake_MainActivity_HNPCInit(   JNIEnv* env,
                                                 jobject /* this */){
    HNPC_Init();
}

//动态注册
extern "C" {
  //调用了libcalStatic.a静态库中的方法
 jint addSum(JNIEnv *env,jobject instance,jint a,jint b,jint c){ //调用静态库
  return  calculAdd(a,b,c);
 }

//调用了libDynamicLibraryTest.so动态库中的方法
 jint jDynamicAdd(JNIEnv *env,jobject instance,jint a,jint b,jint c){
     return dynamicAdd(a,b,c);
 }

//调用了libDynamicLibraryTest.so动态库中的方法
 jstring jGetDynamicName(JNIEnv *env,jobject instance,jstring firstName,jstring lastName){
     char * name= getDynamicName((char*)env->GetStringUTFChars(firstName,0),
                                 (char*)env->GetStringUTFChars(lastName,0));
     return env->NewStringUTF(name);;
 }


 //入门程序  hello form c++
jstring stringFromJNI(JNIEnv *env, jobject instance) {
    std::string hello = "Hello from C++  动态注册";
    return env->NewStringUTF(hello.c_str());
}

//内部自定义c函数的调用,非第三方库
jint add(JNIEnv *env, jobject clazz, jint a, jint b) {
    return a + b;
}

/**
 * Native层,改变Java层对象的属性
 */
void changeName(JNIEnv *env, jobject clazz, jobject person){
    //获取person class对象
    //FindClass("com/gitbaike/cmake/model/Person"); 这里获取的是class类,不是对象
    jclass  personObject=env->GetObjectClass(person);//这里获取的是对象
    //获取setName方法的方法ID
    jmethodID setNameId=env->GetMethodID(personObject,"setName", "(Ljava/lang/String;)V");

    char *setNewName="Native 层赋予你的新名字:";
    jstring str=env->NewStringUTF(setNewName);
    //这里注意,第一个参数需要是jobject对象,所以传入的是person,而不是personObject(jclass对象)
    env->CallVoidMethod(person,setNameId,str);
}


/**
 * Native层,返回一个新的Person对象
 */
jobject getNewPerson(JNIEnv *env,jobject clazz){
    jclass newPerson= env->FindClass("com/gitbaike/cmake/model/Person");
    jmethodID personMethod=env->GetMethodID(newPerson,"<init>", "(ILjava/lang/String;)V");
    jint  age=88;
    char * name="gitbaike";
    jstring jName=env->NewStringUTF(name);
    jobject  person=env->NewObject(newPerson,personMethod,age,jName);
    return person;
}

/**
 * Native层,返回一个新的Person对象集合
 * 返回java层一个list
 */
jobject getListPerson(JNIEnv *env,jobject clazz){
//因为list是无法实例对象,找到Arraylist,返回class对象
    jclass jclass1 = env->FindClass("java/util/ArrayList");
    //拿到构造函数id
    jmethodID contructMethod = env->GetMethodID(jclass1,"<init>","()V");
    //生成一个Arraylist对象,就是我们要返回的对象
    jobject list = env->NewObject(jclass1,contructMethod);
    //拿到 list的 add方法的methodId,准备往method添加几个数据
    jmethodID methodAdd = env->GetMethodID(jclass1,"add","(Ljava/lang/Object;)Z");
    //拿到Person的class对象
    jclass studentClass = env->FindClass("com/gitbaike/cmake/model/Person");
    //拿到person的构造函数的methodId
    jmethodID jmethodID1 = env->GetMethodID(studentClass, "<init>", "(ILjava/lang/String;)V");
    for(int i =1;i<=4;i++){
        char * name="tl";
        char newName[50]="";
//        std::to_string(i)
//       char * iStr=( char *)i;
        strcat (newName, name);
        char * is=reinterpret_cast<char*>(&i);
        strcat (newName, is);
        jobject person = env->NewObject(studentClass,jmethodID1,i,env->NewStringUTF(newName));
        //调用 list的add方法,因为返回时boolean值,所以CallBooleanMethod
        env->CallBooleanMethod(list,methodAdd,person);
    }
    return list;
}

//动态注册
jint RegisterNatives(JNIEnv *env) {
    jclass clazz = env->FindClass("com/gitbaike/cmake/MainActivity");
    if (clazz == NULL) {
        LOGE("con't find class: com/gitbaike/cmake/MainActivity");
        return JNI_ERR;
    }
    JNINativeMethod methods_MainActivity[] = {
            {"stringFromJNI", "()Ljava/lang/String;", (void *) stringFromJNI},
            {"add",           "(II)I",                (void *) add},
            {"changePersonName", "(Lcom/gitbaike/cmake/model/Person;)V",(void *) changeName},
            {"getPerson", "()Lcom/gitbaike/cmake/model/Person;",(void *)getNewPerson},
            {"getPeronList", "()Ljava/util/List;",(void *) getListPerson},
            {"addSum", "(III)I",(void *)addSum},
            {"dynamicAdd", "(III)I",(void *) jDynamicAdd},
            {"getDynamicName", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;",(void *) jGetDynamicName}
    };
    // int len = sizeof(methods_MainActivity) / sizeof(methods_MainActivity[0]);
    return env->RegisterNatives(clazz, methods_MainActivity,
                                sizeof(methods_MainActivity) / sizeof(methods_MainActivity[0]));
}

jint JNI_OnLoad(JavaVM *vm, void *reserved) {
    JNIEnv *env = NULL;
    if (vm->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK) {
        return JNI_ERR;
    }
    jint result = RegisterNatives(env);
    LOGD("RegisterNatives result: %d", result);
    return JNI_VERSION_1_6;
}

}

第三步:Android Java层调用JNI native函数

java调用:

package com.gitbaike.cmake;

import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;

import com.gitbaike.cmake.databinding.ActivityMainBinding;
import com.gitbaike.cmake.model.Person;
import com.google.gson.Gson;

import java.util.List;

import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";

    // Used to load the 'cmake' library on application startup.
    static {
        System.loadLibrary("cmake");
    }

    private ActivityMainBinding binding;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        binding = ActivityMainBinding.inflate(getLayoutInflater());
        setContentView(binding.getRoot());

//         Example of a call to a native method
        TextView tv = binding.sampleText;
        tv.setText(stringFromJNI());

        HNPCInit();

        Person person=new Person();
        person.setAge(12);
        person.setName("java person");

        Log.d(TAG,"调用本地方法前: person.getName:"+person.getName());
        changePersonName(person);
        Log.d(TAG,"调用本地方法后: person.getName:"+person.getName());

        Person nPerson=getPerson();
        Log.d(TAG,"调用本地方法 getPerson()后: person:"+nPerson.toString());

        List<Person> personList=getPeronList();
        Log.d(TAG,"调用本地方法 getPerson()后: personList:"+new Gson().toJson(personList) );

        Log.d(TAG,"调用本地方法 (引用第三方静态库.a)addSum:"+addSum(10,15,65));

        Log.d(TAG,"调用本地方法 (引用第三方动态库.so)dynamicAdd:"+dynamicAdd(100,200,300));

        Log.d(TAG,"调用本地方法 (引用第三方动态库.so)getDynamicName:"+getDynamicName("hello","  https://nav.vpssw.com  --->程序员网址导航<---"));
    }

    /**
     * A native method that is implemented by the 'cmake' native library,
     * which is packaged with this application.
     */
    public native String stringFromJNI();

    public native void HNPCInit();

    public native int add(int a,int b);

    public  native void changePersonName(Person mPerson);

    public native Person getPerson();

    public native List<Person> getPeronList();

    public native int addSum(int a,int b,int c);


    public native int dynamicAdd(int a,int b,int c);

    public native String getDynamicName(String firstName,String lastName);

}

源码已经上传:https://download.csdn.net/download/qingfeng812/88301421

android studio cmake生成.a文件(静态库)及调用(c c++)静态库.a
android studio cmake生成so文件(动态库)及调用(c c++)动态库.so
java调用c函数 c函数调用java
jni静态注册与动态注册。
代码都是我跑通过的。
运行环境
as版本:Android Studio Giraffe | 2022.3.1 Patch 1
android AGP 8.1.1
gradle 版本8.0
jdk 17

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/975873.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Python可复用函数的 6 种最佳实践

对于在一个有各种角色的团队中工作的数据科学家来说&#xff0c;编写干净的代码是一项必备的技能&#xff0c;因为&#xff1a; 清晰的代码增强了可读性&#xff0c;使团队成员更容易理解和贡献于代码库。 清晰的代码提高了可维护性&#xff0c;简化了调试、修改和扩展现有代码…

【机组】计算机系统组成课程笔记 第一章 计算机系统概论

1.1 计算机的基本概念 电子计算机是一种不需要人工直接干预&#xff0c;能够自动、高速、准确地对各种信息进行处理和存储的电子设备。 1.1.1 存储程序的工作方式 1. 单一的处理部件 2. 存储单元是定长的线性组织 3. 存储空间的单元直接寻址 4. 使用低级机器语言&#xf…

基于Hugo 搭建个人博客网站

目录 1.环境搭建 2.生成博客 3.设置主题 4.将博客部署到github上 1.环境搭建 1&#xff09;安装Homebrew brew是一个在 macOS 操作系统上用于管理软件包的包管理器。类似于centos下的yum或者ubuntu下的apt&#xff0c;它允许用户通过命令行安装、更新和管理各种软件工具、…

JavaScript 执行上下文和作用域链

1 执行上下文 执行上下文决定了变量和函数可以访问哪些数据。 一个执行上下文就对应一个仅后台可访问的变量对象&#xff0c;其中保存有该上下文的局部变量、参数和函数声明。 最外层的上下文称为全局上下文。宿主环境不同&#xff0c;全局上下文的关联对象就不同。在浏览器…

在ubuntu20.04上安装arm-linux-gcc 4.4.3

1下载地址 [http://www.friendlyelec.com.cn/download.asp] 2.将 arm-linux-gcc-4.4.3.tar.gz 拷贝到 /bin目录 无法拷贝怎么办&#xff1f; 出现这种情况是 Linux 拷贝文件时权限不够&#xff0c; 运行命令 sudo nautilus&#xff0c; 打开一个具有管理员权限的文件管理器&am…

C# 子类如何访问子类的方法(同一父类)

在继承关系中&#xff0c;子类可以通过创建另一个子类的对象来访问其方法。下面是一个示例&#xff0c;展示了子类如何访问另一个子类的方法&#xff1a; public class Animal {public virtual void Speak(){Console.WriteLine("我是动物。");} }public class Cat :…

直播平台源码开发搭建APP的DASH协议:流媒体技术其中一环

在直播平台源码APP中&#xff0c;有着许许多多、多种多样的功能&#xff0c;比如短视频功能&#xff0c;帮助我们去获取信息&#xff0c;看到全世界用户身边发生的事情或是他们的生活&#xff1b;又比如直播功能&#xff0c;为用户提供了实时的娱乐享受&#xff0c;还让一些用户…

嬴图Ultipa | 实时图计算如何将反洗钱进行到底?

电影《孤注一掷》中&#xff0c;首度曝光了境外网络诈骗全产业链黑幕&#xff0c;而洗钱是最为关键的一环。 王大陆饰演的赌徒阿天将偷和抵押房产凑够的800万元一次性汇入欺诈团伙的博彩账户&#xff0c;由于涉及大额资金流动&#xff0c;警方已经开始监控。令人意外的是&#…

访问局域网内共享文件时报错0x80070043,找不到网络名

我是菜鸡 此篇只为分享一个我遇到的很简单的但是排查了好久的小问题。 我的网络环境是在校园网内&#xff0c; 自己的办公电脑设置了固定IP&#xff1a;10.11.128.236&#xff0c;同事电脑IP为&#xff1a;10.11.128.255 本人需要访问同事在局域网内分享的文件&#xff0c;…

统计学极简入门——数据分布

3. 数据分布 t分布、F分布和卡方分布是统计学中常用的三种概率分布&#xff0c;它们分别用于样本均值的推断、方差的比较和数据的拟合优度检验。 总之这3个分布很有用&#xff0c;首次接触你可能理解不了&#xff0c;但没关系你知道很重要就行了&#xff0c;接着往下看&#…

6.xpath的基本使用

xpath是python做数据解析的库 目录 1 安装 2 解析本地的html文件 2.1 只有一个标签的情况 2.2 有多个标签的情况 3 解析网上的页面 4 xpath表达式 4.1 绝对路径 4.2 两个斜杠表示中间隔了0级或多级 4.3 通过属性查找 4.4 通过索引查找 4.5 获取文本内容…

JavaScript-----运算符与流程控制

目录 前言&#xff1a; 1. 运算符 1.1 算术运算符 1.2 赋值运算符 1.3 比较运算符 1.4 逻辑运算符 2.流程控制 1.1 分支结构 switch语句 1.2 循环结构 while 循环 for循环 循环控制 : 1.3代码示例 前言&#xff1a; 今天我们就开始学习JavaScript里面的运算符和流…

【校招VIP】测试开发之字符串算法

考点介绍&#xff1a; 字符串匹配看起来是个很简单、很成熟的问题&#xff0c;但在很多领域都有着很多的应用&#xff0c;比如模式匹配、特征提取等等。字符串算法是很经典的面试题&#xff0c;既考察了求职者的写用例水平又考察了软件测试求职者的编码水平。 测试开发之字符串…

景联文数据标注:AI大模型在教育和医疗领域的应用

8月31日消息&#xff0c;备受行业瞩目的首批大模型产品获批名单发布&#xff0c;首批通过备案的8家大模型公司分别是&#xff1a;百度&#xff08;文心一言&#xff09;、抖音&#xff08;云雀大模型&#xff09;、智谱AI&#xff08;GLM大模型&#xff09;、中科院&#xff08…

centos7上hive3.1.3安装及配置

1、安装背景&#xff1b; hive是基于hadoop的数据仓库软件&#xff0c;部署运行在linux系统之上&#xff0c;安装之前必须保证hadoop环境运行正常&#xff0c;hive本身不是分布式软件&#xff0c;它的分布式主要是借助hadoop实现&#xff0c;存储是hdfs&#xff0c;计算是mapr…

彻底学会Unity从网上加载资源到场景

使用类WWW 该类实例化的对象可以存储多种多媒体资源&#xff0c;只需要在构造函数中附上可访问的资源链接 Unity 中&#xff0c;WWW 类用于实例化互联网上的资源&#xff0c;如文本、图像、音频和视频等。WWW 实例化的对象可以存储多种多媒体素材。以下是一些常见的例子&…

Kubernetes(k8s) 架构原理一文详解

目录 一、k8s 概述 1.什么是k8s&#xff1f; 2.特性 3.主要功能 三、集群架构与组件 1.Master 组件 &#xff08;1&#xff09;Kube-apiserver &#xff08;2&#xff09;Kube-controller-manager &#xff08;3&#xff09;Kube-scheduler 2.配置存储中心 3.Node 组…

Cell Reports | 揭开METTL14在介导m6A修饰中的神秘面纱

m6A被认为是最丰富的mRNA修饰&#xff0c;广泛分布在大多数真核生物中&#xff0c;包括哺乳动物、植物、昆虫、酵母和某些病毒。m6A修饰的沉积和去除之间的动态平衡对于正常的生物过程和发育至关重要&#xff0c;如失调通常与癌症等疾病有关。m6A修饰由m6A甲基转移酶复合物&…

C++多态案例3----组装电脑含测试代码

案例描述: 电脑主要组成部件为 CPU (用于计算) &#xff0c;显卡 (用于显示) &#xff0c;内存条 (用于存储)将每个零件封装出抽象基类&#xff0c;并且提供不同的厂商生产不同的零件&#xff0c;例如Intel厂商和Lenovo厂商创建电脑类提供让电脑工作的函数&#xff0c;并且调用…

nc前端合计行、按钮组

nc前端合计行、按钮组 1.无表体和单表体的合计行加法 只要卡片下 如果是只有表头要合计行就只留ShowTotalLine&#xff1b;如果是只有表体要合计行就只留ShowTotalLineTabcodes 2.多表体的合计行加法 表头卡片下和列表下都要 3.档案的合计行加法 重写一下列表模板 …