sheldon_blogs

Android:JNA实践(附Demo)

一、JNA和JNI的对比

  1.JNI的调用流程
  Android应用开发中要实现Java和C,C++层交互时,想必首先想到的是JNI,但是JNI的使用过程十分繁琐,需要自己再封装一层JNI接口进行转换(使用SUN规定的数据结构去替代C语言的数据结构),包名、函数名等都要匹配,难以阅读和更新。
  如下图是通过JNI实现Java调用C层的方法流程:
  

  2.什么是JNA?与JNI有什么差异?

  JNA(Java Native Access):建立在JNI之上的Java开源框架,SUN主导开发,用来调用C、C++代码,尤其是底层库文件(windows中叫dll文件,linux下是so【shared object】文件)。JNA简化了Java调用原生函数的过程,原理是提供了一个动态的C语言编写的转发器(实际上也是一个动态链接库,在Linux-i386中文件名是:libjnidispatch.so)可以自动实现Java与C之间的数据类型映射。
  相比JNI,JNA只需要导入一个.jar和一个.so,然后就可以在Java中直接声明so中公开的函数并调用,十分方便。而JNA有两个小缺点:(1)性能上会比通过JNI调用动态链接库要稍低,但总体影响不大,因为JNA也避免了JNI的一些平台配置的开销。(2)因为JNA调用是直接在Java层实现,所以反过来C层无法直接通过JNA调用Java方法,但是Java层可以把方法模拟函数指针传到c层进行回调。
 
  

 

 二、JNA实践
 
  1. jna.jar包和libjnidispatch.so库文件下载
  
     JNA项目的Git Hub地址:https://github.com/java-native-access/jnalibjnidispatch.so 包含在android-armv7.jar中,以及jna.jar 都在 dist 目录下。
  
  2.导入jar包和so到Android studio工程
  (1)目录结构
    

 

  (2)build.gradle 配置

复制代码
apply plugin: 'com.android.library'

android {
    ......
    sourceSets{
        main{
            jniLibs.srcDirs = ['src/main/jniLibs']
        }
    }
    ......
}

dependencies {
    implementation fileTree(include: ['*.jar'], dir: 'libs')
    ......      
}
复制代码

 

   3.代码实现
     (1)新建一个Java接口直接加载第三方动态库 libnanovoice.so

    其中libnanovoice.so对于应的头文件(.h)内容如下:

复制代码
#ifndef __JB_NANOSIC__H__
#define __JB_NANOSIC__H__

#ifdef __cplusplus
extern "C" { 
#endif

typedef void (*AppCallback) (char* data,int datalen);

int nano_open(AppCallback cb);
int nano_close(void);

#ifdef __cplusplus
}
#endif


#endif
复制代码

    根据动态库提供的头文件里函数声明,编写JnaNanovoice.java 内容如下:

复制代码
package com.lxl.nanosic.voice;

import com.sun.jna.Callback;
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.NativeLibrary;
import com.sun.jna.Pointer;

public interface JnaNanovoice extends Library {
    public static final String JNA_LIBRARY_NAME = "nanovoice";
    public static final NativeLibrary JNA_NATIVE_LIB = NativeLibrary.getInstance(JnaNanovoice.JNA_LIBRARY_NAME);
    public static final JnaNanovoice INSTANCE = (JnaNanovoice)Native.loadLibrary(JnaNanovoice.JNA_LIBRARY_NAME, JnaNanovoice.class); //直接加载第三方动态库

    //定义接口AppCallback,继承自com.sun.jna.Callback
    public interface AppCallback extends Callback {
        void dataReceived(Pointer data, int datalen);
    }

    //动态库的函数声明
    int nano_open(AppCallback cb);
    int nano_close();
}
复制代码

  c层和JNA层变量类型有所差异,需要转换:

  推荐一个转换工具 :jnaeratorStudio.jar   使用方法:java -jar jnaeratorStudio.jar

 

  (2)调用c库函数,其中Java回调接口需要进一步实现, NanoVoiceRecord.java 中JNA调用部分代码截取如下:

复制代码
package com.lxl.nanosic.voice;

import android.util.Log;
import com.sun.jna.Pointer;
import java.util.LinkedList;

public class NanoVoiceRecord {

    private final String TAG = "NanoVoiceRecord";/**
     * 回调函数
     */
    private static JnaNanovoice.AppCallback mDataCallback;

......

  /** API 2:开始录音 **/ public void start() {   ......
    // JNA接口 mDataCallback = new JnaNanovoice.AppCallback() { // 实现接口中的回调 public void dataReceived (Pointer data, int datalen){ if(null != data){ byte[] buffer = data.getByteArray(0, datalen); int res = OnDataReceived(buffer, datalen); Log.w(TAG, "...OnDataReceived = " + res + "m_in_q.size=" + m_in_q.size()); } else { Log.e(TAG, "...Callback data is null !!!"); } } }; // 开始录音并传入回调 JnaNanovoice.INSTANCE.nano_open(mDataCallback); } /** API 3:停止录音 **/ public void stop() { JnaNanovoice.INSTANCE.nano_close(); //调用JNA接口退出录音 isRecording=false; } ......

  /** * 处理c层回调上来的遥控器语音数据方法 */ public int OnDataReceived(byte[] buffer, int size) { byte[] bytes_pkg; int bufferLength; if(m_in_q==null){ return 0; } bytes_pkg = buffer.clone(); if (m_in_q.size() > 6) { //最多缓存6个包 m_in_q.removeFirst(); } m_in_q.add(bytes_pkg); ...... }
复制代码

  

  至此便实现了Java层通过JNA对c层函数的直接调用:

 

   JNA实践Demo(包含转换jar工具)已传至Git Hub : https://github.com/dragonforgithub/JnaDemo
 
 

posted on   sheldon_blogs  阅读(7858)  评论(0编辑  收藏  举报

编辑推荐:
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
阅读排行:
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

导航

统计

点击右上角即可分享
微信分享提示