相关开源库
https://github.com/ikvm-revived
版本号
IKVM 在 8.2.0 版本中新增加 IkvmReference
(在 MSBuild 中配置. 自动帮你编译jar到dll 和 自动引用dll )
所以本文就用这个了.
不再使用 ikvmc 手动编译, 太繁琐了,
手动输入 ikvm -jar 和 ikvmc 有 java -jar 和 javac 的感觉了.
nuget 第一次安装 ikvm 可能需要点时间,
因为 ikvm 的 dll 比较大. 耐心等待一下.
会保存到 C:\Users\Administrator\.nuget\packages\ikvm\
以后安装同版本的 ikvm 就不用再重复下载了.
说明
首先得有 Java 代码
本文使用
java 的 SM2 加密 (测试自己写的java代码)
和 hutool 中的 简易 FTP 来举例 (测试 第三方依赖 +二级依赖)
SM2 中也使用了 hutool
Java Maven 部分
直接创建一个 Maven 空项目, 开始写代码.
第一部分是 依赖项
第二部分是 打包代码和依赖到一个jar中 (下面有说明为什幺要打包成一个jar)
代码写完后, 在IDEA右侧的 maven 里 双击 package 进行打包.
就会看到输出目录有一个 8.9M 的 netjar.jar
( 如果你只有别人提供的jar包, 也可以 手动执行 jar包的解压和压缩. 把多个jar合成一个 ,
如果只有class文件, 那就得手动创建多层文件夹 和 java 的 package 名称匹配上. 再用命令 压缩为jar)
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.xue</groupId>
<artifactId>netjar</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<!-- 依赖-->
<dependencies>
<!-- hutool 和 依赖的ftp包-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.5</version>
</dependency>
<dependency>
<groupId>org.apache.ftpserver</groupId>
<artifactId>ftpserver-core</artifactId>
<version>1.2.0</version>
</dependency>
<!-- 加密相关-->
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.70</version>
</dependency>
<!-- 一些工具类-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.36</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.12.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<!-- 将所有依赖打包到一个jar中-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.4</version>
<configuration>
<appendAssemblyId>false</appendAssemblyId>
<finalName>netjar</finalName>
<descriptorRefs>
<!-- 将依赖的jar包中的class文件打进生成的jar包-->
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<!--
Main函数的类,生成的jar包 使用命令执行时的入口函数,
如果不需要一个入口. 那就可以随便写一个 唯一的类就行. 不影响
-->
<mainClass>com.xue.netjar.Main</mainClass>
</manifest>
</archive>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<!-- <goal>single</goal>-->
<goal>assembly</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
为什么要打包成1个 jar ?
如果每个依赖都打1个包, 那这里会出现9个jar ,
就得在.csproj 配置中 写9遍 指定jar位置 (可能以后会支持指定文件夹吧),
打包成1个就只需要写1遍了.
其实只指定jar位置还不行, IKVM 在执行代码时 , 就会说 找不到 XXX 依赖.
所以你还需要指定依赖 References
,
例子中的 h1 h2 h3 都是 常规的 第三方依赖 , 比如 hutool,
my-code 是 自己写的代码. (java 写的SM2加密)
<ItemGroup>
<IkvmReference Include="files/h1.jar"/>
<IkvmReference Include="files/h2.jar"/>
<IkvmReference Include="files/h3.jar"/>
<IkvmReference Include="my-code.jar">
<AssemblyName>MyCode</AssemblyName>
<AssemblyVersion>1.0.0.0</AssemblyVersion>
<References>files/h1.jar;files/h2.jar;files/h3.jar;</References>
</IkvmReference>
</ItemGroup>
真实写法, jar包多了, 那就太痛苦了.
<IkvmReference Include="jar/bcprov-jdk15on-1.64.jar" />
<IkvmReference Include="jar/commons-lang3-3.12.0.jar" />
<IkvmReference Include="jar/hutool-all-5.6.3.jar" />
<IkvmReference Include="jar/Sm2Util.jar" >
<AssemblyName>Sm2Util</AssemblyName>
<AssemblyVersion>1.0.0.1</AssemblyVersion>
<References>jar/hutool-all-5.6.3.jar;jar/bcprov-jdk15on-1.64.jar;jar/commons-lang3-3.12.0.jar</References>
</IkvmReference>
这种配置文件形式, 估计底层也是调用旧的命令方式去转为dll ( 可以看到很多老文章都是手动 搞 ikvmc 命令)
所以我们要打包成一个jar, 不用写一堆 Include , 也不用 写一堆 References 了
省了不少事情, 直接 写一个 Include , 啥也不用操心了.
C# 部分
在vs中新建一个名为jar的文件夹, 把 netjar.jar 放进来.
在 .csproj
中添加 IkvmReference
, 再添加 Include 为 jar/netjar.jar
指定 AssemblyName
( 编译后的 就是 netjar.dll ) (其他的第三方包不用指定, 会自动识别)
AssemblyVersion
必须是 1.0.0.0 这种 4部分的版本号, 会给dll加上版本信息. (估计内部会根据版本号缓存dll)
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="IKVM" Version="8.2.1" />
</ItemGroup>
<ItemGroup>
<IkvmReference Include="jar/netjar.jar" >
<AssemblyName>netjar</AssemblyName>
<AssemblyVersion>1.0.0.4</AssemblyVersion>
</IkvmReference>
</ItemGroup>
</Project>
保存后, 重新生成下 解决方案.
此时 写代码 应该已经有 智能提示了.
最终测试一下
非常的完美哦. 功能都正常.
namespace IkvmDemo;
using cn.hutool.core.util;
using cn.hutool.extra.ftp;
using cn.hutool.http;
using cn.hutool.http.server;
using cn.hutool.http.server.action;
using com.xue.netjar; // 自己用java写的 SM2
internal class Program
{
static void Main(string[] args)
{
//*******************
// 测试一下 Java 的 SM2 加密
//var res2 = new Sm2Util()
// .encrypt(
// "我是内容",
// "publicKey太长,省略了.",
// "GBK");
//Console.WriteLine(res2);
//*******************
// 调用一下 java 的 main 方法
//com.xue.netjar.Main.main(args);
//*******************
// 测试一下 hutool 的 IdCard 帮助类. 获取 归属地
//var idCard = "142731195005152222";
//var res = IdcardUtil.getProvinceByIdCard(idCard);
//Console.WriteLine(res);
//*******************
// 启动 Ftp
//SimpleFtpServer.create().addAnonymous("E:/").start();
//**************
// 启动 http服务器
HttpUtil.createServer(8000).addAction("/", new MyAction()).start();
//Console.ReadLine();
}
}
// 有点小遗憾, c#没有 匿名内部类, 只能写一个完整的类, 去实现 hutool 的 Action 接口
public class MyAction : Action
{
public void doAction(HttpServerRequest req, HttpServerResponse res)
{
res.write("hi");
}
}
目录结构
题外话
2022.08.11
https://github.com/ikvm-revived/ikvm-maven
发现作者新开了一个仓库, 这是要给 IKVM 扩展一个 C# 里的 maven 呀
直接 指定一个包名称和版本号, 就能从 maven 仓库 自动拉取依赖. 不用自己折腾本地jar包了.
和 java 用 maven 一模一样.
不过还处在早期 ( 刚写1个月 ), 只实现了基本的 单包拉取 ,
还不会自动分析依赖.
也不能手动指定 之前那个 References 依赖,
执行代码的时候还是会报 找不到xxx依赖
2022.08.11
看 IKVM 的 issues , 好像作者 最近已经开始 兼容 JDK9. (要兼容到最新JDK的节奏? )
这是要兼容 java 所有生态啊 ,太强了…
如果以后 ikvm-maven 完成, 写个包名 直接开始用.
和 C# 用 nuget 一样, 轻轻松松.
那真是无敌了.
2022.08.11
从某个评论区找到一个替代品, 好像是收费的. 也不开源.
https://github.com/masesgroup/JCOBridge-Examples