由于项目中java需要调用第三方提供的C++动态库;由于第三方动态库传入的参数较多,还伴随着指针传入操作,导致java调用极为不便!因此催生出对于第三方的C++动态库进行二次封装。java调用只需按结构传入一个结构化的string即可。话不多说开干!
第三方库
第三方C++的头文件HD10_safe.h如下:
#ifndef _HD10_safe_H_
#define _HD10_safe_H_#ifdef _cplusplus
extern "C" {
#endiftypedef enum VKeyGenResultEx
{KGRE_OK ,KGRE_NOT_OK
}KeyGenResult;typedef enum ECUS
{BCM=1, DCM, IC_6000, GW, VWM, LDWS, DMS, VCU, RCU, ACC, RWCD, PSU, BBM, AC_6000, TPMS, VMS, PEPS, IMMO, EMS, ESCL,MMI, BMS, FC, EC, ECM, CPD_3000, AFS, TCO, TCU, DCU,ECAS, ABS, EBS, EPB, AEBS, EVM, TCU_SH, ADAS, BS_LKA, CIM,RIM, FIM, MCU, CABS, DSW, VCU_x5_M3S, SWG, CCU, WP_ECU, CMS_ECU,EHBS, ACR, TBOX_5G, CSC, HCU, LKA, ADCU, CPD_6000, IC_3000, AC_3000,LE_IC, LE_AC, LE_BCM, LE_GW, LE_VCU, LE_TPMS, LE_DCM, VDCU, PDU, DCDC, DCAC, DSSAD
}ECUs;typedef unsigned char uint8;
typedef unsigned short uint16;
// Function
//
KeyGenResult HD10GenerateKeyEx(uint8* iSeedArray, /* Array for the seed [in] */uint8 iSeedArraySize, /* Length of the array for the seed [in] */const uint8 iSecurityLevel, /* Security level [in] */uint8 * iKeyArray, /* Array for the key [in, out] */uint8 * iKeySize, /* Length of the key [out] */ECUs e /* enum ECUS elements */);#ifdef _cplusplus
}
#endif#endif // _HD10_safe_H_
第三方动态库 libTXJsafe.so 如下:
C++调用
写一个C++ demo 调用动态库 test.cpp 代码如下:
#include <stdio.h>
#include "HD10_safe.h"int main()
{uint8 arr[2] = {0x12, 0x34};uint8 seed[2] = {0x00, 0x00};uint8 seedLen = 0;int ret = HD10GenerateKeyEx(arr, 2, 7, seed, &seedLen, TCU);printf("ret : %d, seedLen:%d \n", ret, seedLen);for(int i = 0; i < seedLen; i++){printf("seed[%d] : 0x%02x ;", i, seed[i]);}printf("\n");return 0;
}
运行结果如下:
jni二次封装动态库
通过jni二次封装动态库 mysafelib.cpp 代码如下:
#include <iostream>
#include <stdio.h>
#include <jni.h>
#include <string.h>
#include "HD10_safe.h"// iString 输入参数格式:level(1byte) + ECUS(1byte) + SeedSize(1byte) + SeedValue(nbyte)
// rString 返回参数格式:keysize(1byte) + keyValue(nbyte)
extern "C" {JNIEXPORT jstring JNICALL Java_com_example_MyClass_nativeMethod(JNIEnv *env, jobject obj, jstring iString);
}// 十六进制字符串转字十六进制 "12" --> 0x12
int Str2Hex(char *p_hexstr, int iHexLen, char *pdststr);// 十六进制数值转十六进制字符串 0x12 --> "12"
int Hex2Str(const char *p_strstr, int iStrLen, char *pdststr);JNIEXPORT jstring JNICALL Java_com_example_MyClass_nativeMethod(JNIEnv *env, jobject obj, jstring iString)
{char myRString[66] = {0};char iHexStrOrg[64] = {0};char iHexStr[32] = {0};const char *iStrData = env->GetStringUTFChars(iString, 0);memcpy(iHexStrOrg, iStrData, strlen(iStrData) > 64 ? 64 : strlen(iStrData));env->ReleaseStringUTFChars(iString, iStrData);int iHexStrLen = Str2Hex(iHexStrOrg, strlen(iHexStrOrg), iHexStr);// std::cout << "strlen(iHexStrOrg) : " << strlen(iHexStrOrg) << std::endl;if(iHexStrLen < 4) return env->NewStringUTF(myRString);// std::cout << "iHexStrLen : " << iHexStrLen << std::endl;uint8 seed[32] = {0};uint8 key[33] = {0};uint8 keyLen = 0;uint8 u8Level = *(uint8 *)iHexStr;uint8 u8ECU = *(uint8 *)(iHexStr + 1);uint8 u8SeedSize = *(uint8 *)(iHexStr + 2);// printf("u8SeedSize : %d \n", u8SeedSize);if(u8SeedSize > 32) return env->NewStringUTF(myRString);memcpy(seed, iHexStr + 3, u8SeedSize);KeyGenResult ret = (KeyGenResult)HD10GenerateKeyEx(seed, u8SeedSize, u8Level, key + 1, &keyLen, (ECUs)u8ECU);if(ret != KGRE_OK || keyLen > 32) return env->NewStringUTF(myRString);// printf("ret : %d, keyLen:%d \n", (int)ret, keyLen);// for(int i = 1; i <= keyLen; i++) printf("key[%d] : %02x; ", i, key[i]);key[0] = keyLen * 2;Hex2Str((const char*)key, keyLen + 1, myRString);jstring rString = env->NewStringUTF(myRString);printf("\n---------------successful-----------------\n");return rString;
}// 十六进制字符串转字十六进制 "12" --> 0x12
int Str2Hex(char *p_hexstr, int iHexLen, char *pdststr)
{int iret = 0;while(p_hexstr != NULL && pdststr != NULL && iHexLen > 1){char cTemp = '0';// printf("1:%c, 2:%c\n", p_hexstr[0], p_hexstr[1]);// 小写统一转大写if(p_hexstr[0] >= '0' && p_hexstr[0] <= '9'){cTemp = p_hexstr[0] - '0';}else if(p_hexstr[0] >= 'A' && p_hexstr[0] <= 'F'){cTemp = p_hexstr[0] - 'A' + 10;}else if(p_hexstr[0] >= 'a' && p_hexstr[0] <= 'f'){cTemp = p_hexstr[0] - 'a' + 10;}else{printf("the hex str is error!\n");break;}*pdststr = cTemp * 16;if(p_hexstr[1] >= '0' && p_hexstr[1] <= '9'){cTemp = p_hexstr[1] - '0';}else if(p_hexstr[1] >= 'A' && p_hexstr[1] <= 'F'){cTemp = p_hexstr[1] - 'A' + 10;}else if(p_hexstr[1] >= 'a' && p_hexstr[1] <= 'f'){cTemp = p_hexstr[1] - 'a' + 10;}else{printf("the hex str is error!\n");break;}*pdststr += cTemp;// printf("---iHexLen:%d, pdststr:%c\n", iHexLen, *pdststr);iHexLen -= 2;p_hexstr += 2;pdststr++;iret++;}// printf("iret : %d\n", iret);return iret;
}// 十六进制数值转十六进制字符串 0x12 --> "12"
int Hex2Str(const char *p_strstr, int iStrLen, char *pdststr)
{int index_str = 0, index_hex = 0;const char cHex[] = "0123456789ABCDEF";while(index_str < iStrLen && p_strstr != NULL && pdststr != NULL){pdststr[index_hex++] = cHex[((uint8)p_strstr[index_str])/16];pdststr[index_hex++] = cHex[((uint8)p_strstr[index_str++])%16];}return index_hex;
}
编译生成对应二次封装的动态库如下:
java调用二次封装动态库
java调用二次封装库的demo文件如下:
package com.example;public class MyClass {static {System.load("/home/lijd/testlib3/sodir/libmysafe.so"); // 加载C++动态库}private native String nativeMethod(String str); // 声明本地方法public static void main(String[] args) {byte[] seedValue = new byte[]{0x12, 0x34};int seedSize = 2;//字节长度int level = 7;int ECUS = 29;StringBuffer param = new StringBuffer();param.append(byteToString(intToByte1(level)));param.append(byteToString(intToByte1(ECUS)));param.append(byteToString(intToByte1(seedSize)));param.append(byteToString(seedValue));String result = new MyClass().nativeMethod(param.toString()); // 调用本地方法System.out.println("---MyClass---" + result.length() + " : " + result);}/*** @title byteToString* @description 将字节数组转为字符串* @param buff* 字节数据* @return String 装换后的字符串数据*/public static final String byteToString(byte[] buff) {StringBuilder sb = new StringBuilder();if (null != buff && buff.length > 0) {for (byte b : buff) {short t = b;if (t < 0)t += 256;short h = (short) (t / 16);short l = (short) (t % 16);switch (h) {case 10:sb.append("A");break;case 11:sb.append("B");break;case 12:sb.append("C");break;case 13:sb.append("D");break;case 14:sb.append("E");break;case 15:sb.append("F");break;default:sb.append(h);break;}switch (l) {case 10:sb.append("A");break;case 11:sb.append("B");break;case 12:sb.append("C");break;case 13:sb.append("D");break;case 14:sb.append("E");break;case 15:sb.append("F");break;default:sb.append(l);break;}}}return sb.toString();}public static byte[] intToByte1(int value) {byte[] b = new byte[1];for (int i = 0; i < 1; ++i) {int offset = (b.length - 1 - i) * 8;b[i] = (byte) (value >>> offset & 255);}return b;}
}
执行javac 编译源文件生产class文件如下:
运行java的class文件如下:
至此,一切搞定!通过windows测试这样也完全可以。