UIpath的methodinvoke可以调用java脚本,在uipath中的配置步骤为引入jdk,引入jar包,然后完善需要调用的方法和类型,
但是实际过程中遇到了许多的问题
1.dll文件处理
如果jar包需要引入一些dll文件,比如我们通过java调用opencv的一些东西,就需要指定dlll文件路径,正常情况下我们可以通过
运行时的-d参数来指定java.library.path,但是在uipath调用中是无法添加参数的
解决办法是通过反射修改ClassLoader的usr_paths字段,将dll文件的路径添加进去即可
2.uipath中的jdk和我们jar包的jdk,或者说opencv的版本需要匹配,否则会报错
3.uipath调用的入口方法不能引入三方依赖的类,否则会调用失败,我们需要将入口尽量简单
4.uipath调用使用Thread.currentThread().getContextClassLoader()会有无法预知的问题,所以获取类加载器最好通过类来获取
5.dll文件处理:在这里我们的jar包需要一些dll文件的依赖,但是我只想一个jar包包含所以,所以,解决方式是:
将依赖统统打入jar包的某一个文件夹,在使用之前,获取到jar内部文件,然后copy到包路径下伪代码如下
static {
File dllFile = new File(JvmUtils.getJarPath()+ "/x64/opencv_java430.dll");
if(!dllFile.exists()) {
InputStream inputStream = ImageCompare.class.getClassLoader().getResourceAsStream("opencv_java430.dll");
JvmUtils.copyFile(inputStream, dllFile);
}
try {
JvmUtils.addLibrarydir(dllFile.getParent());
} catch (Exception e) {
}
}
public static void addLibrarydir(String libraryPath) throws Exception{
try {
Field field = ClassLoader.class.getDeclaredField("usr_paths");
field.setAccessible(true);
String[] path = (String[])field.get(null);
for(int i = 0 ;i < path.length ; i++) {
if(libraryPath.equals(path[i])) {
return ;
}
}
String[] tmp = new String[path.length+1];
System.arraycopy(path, 0, tmp, 0, path.length);
tmp[path.length] = libraryPath ;
field.set(null, tmp);
} catch (Exception e) {
throw e ;
}
}
public static boolean copyFile(InputStream source , OutputStream target) {
try {
byte[] data = new byte[1024] ;
int length = -1 ;
while((length = source.read(data)) > 0) {
target.write(data, 0, length);
}
target.flush();
} catch (Exception e) {
return false ;
}finally {
close(source,target);
}
return true ;
}
public static boolean copyFile(InputStream source , File target ) {
if(source == null) {
return false ;
}
if(!target.getParentFile().exists()) {
target.getParentFile().mkdirs();
}
FileOutputStream os = null ;
try {
os = new FileOutputStream(target);
return copyFile(source, os);
} catch (FileNotFoundException e) {
return false ;
}
}