一次JAVA调用C++的.so库的过程

发布时间:2023年12月29日

1、准备好.so文件

2、java代码引入jna jar包

<dependency>
     <groupId>net.java.dev.jna</groupId>
     <artifactId>jna</artifactId>
     <version>5.9.0</version>
</dependency>

3、代码实现

package com.jimi.tracker.util;

import com.google.common.collect.Lists;
import com.sun.jna.Library;
import com.sun.jna.Native;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

/**
 * Description:
 * <p>
 * SO的
 * </p>
 *
 * @Author: leo.xiong
 * @CreateDate: 2023/12/27 20:19
 * @Email: xionglang@jimilab.com
 * @Since:
 */
public class JnaUtil {
    private static final Logger LOGGER = LoggerFactory.getLogger(JnaUtil.class);

    private static final String OS;

    private static final boolean IS_WIN;

    private static final String ENCODE = "encode";

    private static final String USR_LIB_JIMI_SO = "/usr/lib/jimi";

    private static final String SO = ".so";
	/**
	* 需要使用的so文件
	*/
    private static final List<String> SO_NAME_LIST = Lists.newArrayList(ENCODE);

    static {
        OS = System.getProperty("os.name").toUpperCase();
        IS_WIN = OS.contains("WIN");
        if (!IS_WIN) {
            //动态设置JNA参数,如果不动态设置,需要通过-Djna.library.path=/usr/lib/jimi/so 指定JVM参数,so文件名需要lib开头
            //System.setProperty("jna.library.path", USR_LIB_JIMI_SO + "/so");
            //在当前jar包的resouce/so文件夹,把so文件放入其中
            extractSoFromJar(JnaUtil.class.getProtectionDomain().getCodeSource().getLocation().getPath(), USR_LIB_JIMI_SO);
        }
    }

    /**
     * 加载Jar包中的so文件
     *
     * @param jarPath
     * @param extractPath
     */
    private static void extractSoFromJar(String jarPath, String extractPath) {
        File jarFile = new File(jarPath);
        try (JarFile jar = new JarFile(jarFile)) {
            Enumeration<JarEntry> entries = jar.entries();
            while (entries.hasMoreElements()) {
                JarEntry entry = entries.nextElement();
                if (!entry.getName().toLowerCase().endsWith(SO)) {
                    continue;
                }
                boolean isCopy = false;
                for (String soName : SO_NAME_LIST) {
                    if (entry.getName().contains(soName)) {
                        isCopy = true;
                    }
                }
                if (!isCopy) {
                    continue;
                }
                File outputFile = new File(extractPath, entry.getName());
                if (outputFile.exists()) {
                    //文件已存在,先删除旧的so文件
                    LOGGER.info("文件已存在,先删除旧的so文件:{}", extractPath + "/" + entry.getName());
                    outputFile.delete();
                }
                outputFile = new File(extractPath, entry.getName());
                if (!outputFile.getParentFile().exists()) {
                    outputFile.getParentFile().mkdirs();
                }
                try (InputStream is = jar.getInputStream(entry);
                     OutputStream os = new FileOutputStream(outputFile)) {
                    byte[] buffer = new byte[1024];
                    while (is.read(buffer) > 0) {
                        os.write(buffer);
                    }
                } catch (IOException ioException) {
                    LOGGER.warn("读取.so文件失败 fileName: {}", entry.getName(), ioException);
                }
            }
        } catch (IOException ioException) {
            LOGGER.warn("获取.so库失败 jarPath: {} extractPath: {}", jarPath, extractPath, ioException);
        }
    }

    /**
     * 调用C加密库
     *
     * @param imei
     * @param chipId
     * @param type
     * @return
     */
    public static String encryptValue(String imei, String chipId, Integer type) {
        byte[] encryptBytes = new byte[32];
        try {
            if (IS_WIN) {
                return imei;
            }
            EncodeLibrary.INSTANCE.ImeiChipEncrypt(encryptBytes, imei, chipId, type);
        } catch (Exception e) {
            LOGGER.warn("加密值获取错误 imei:{} chipId: {} type: {}", imei, chipId, type, e);
            return null;
        }
        return new String(encryptBytes, StandardCharsets.UTF_8);
    }


    /**
     * 调用加密方法
     */
    public interface EncodeLibrary extends Library {
        /**
         * 加密文件名称,指定 JVM参数,文件放在这个路径下面 -Djna.library.path=/usr/lib
         * linux 文件名使用lib开头,如文件名【libencode.so】,加载的时候需要去掉lib,使用【encode】
         */
        EncodeLibrary INSTANCE = Native.load(ENCODE, EncodeLibrary.class);

        /**
         * 调用C++加密方法,名称跟.h文件相同
         *
         * @param output
         * @param imei
         * @param chip
         * @param mode
         */
        void ImeiChipEncrypt(byte[] output, String imei, String chip, Integer mode);
    }

    public static void main(String[] args) {
        byte[] encryptBytes = new byte[32];
        EncodeLibrary.INSTANCE.ImeiChipEncrypt(encryptBytes, "123456789123123456789", null, 0);
    }
}
文章来源:https://blog.csdn.net/xionglangs/article/details/135274761
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。