java JNI调用C++代码(给出一个简单java application示例和实际java web项目过程及错误解决)(二)

二、java web 服务器(tomcat)调用图像处理C++代码项目实例

转载请注明:https://blog.csdn.net/xitie8523/article/details/80009821

简单JNI示例:https://blog.csdn.net/xitie8523/article/details/79926948

菜鸟在开始写代码时担心的是 

1、我图像处理的方法封装了那么多方法,不可能一个一个声明为native,如果我只声明最后封装的那个方法,其他的.h文件不管,会不会出问题?

2、图像处理用了opencv库,在java里面是不是也要配置一下?

3、处理个图像很费事的,会不会崩了?

4、除了让C++方法能调用,还要把它整合到服务器里调用,在服务器哪里调用,怎么把数据返回?

叨叨完了,正文:

1)第一步同样是编写java源码

事先已经搭好了服务器和客户端,由Upload实现互传图片,在包trans下新建一个java类GrainCutDll,其中GrainCutDll是我C++工程名,也可以改成其他的名字,imageProcess()是封装的图像处理方法。


源码:

package trans;


public class GrainCutDll 
{
	static{
		//System.load("D:/Program Files/vs2010project/graduation_project/GrainCutDll/x64/DebugGrainCutDll.dll");
		//System.out.println( System.getProperty("java.library.path") ); 
		System.loadLibrary("GrainCutDll"); //调用的C++的.dll文件
	}
    public native static int imageProcess(String path); //调用的C++方法 
	     


}
2).class和.h文件

按照简单JNI示例:https://blog.csdn.net/xitie8523/article/details/79926948中的方法生成两个文件。

3)vs2013新建工程

打开vs2013,文件——>新建——>项目——>选择win32控制台程序(或者win32项目都可)——>改名称——>确定



点击下一步,选中Dll和空项目,然后完成

4、生成Dll文件

将trans_GrainCutDll.h作为头文件添加到工程里面,新建GrainCutDll.cpp源文件,并将jni.h和jni_md.h作为外部依赖文件导入工程,具体如下:

打开属性管理器——>右击——>点击属性——>转到VC++/常规/附加包含目录 ——>添加文件夹,这里我是把两个.h文件新建一个external_h(随便起的名)文件夹,然后将这个文件夹添加到附加包含目录里



生成的trans_GrainCutDll.h文件
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class trans_GrainCutDll */

#ifndef _Included_trans_GrainCutDll
#define _Included_trans_GrainCutDll
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     trans_GrainCutDll
 * Method:    imageProcess
 * Signature: (Ljava/lang/String;)I
 */
JNIEXPORT jint JNICALL Java_trans_GrainCutDll_imageProcess
  (JNIEnv *, jclass, jstring);

#ifdef __cplusplus
}
#endif
#endif
GrainCutDll .cpp源文件与一般的C++程序不同的是没有main函数。我在写的时候是直接把我原来的C++程序中imageProcess方法换了个方法名(按.h文件),直接copy过来,而原来工程里面的main就不要了。要记得图像处理函数包含的.h文件依旧要包含,另外还要包含trans_GrainCutDll.h和jni.h与jni_md.h。最后生成就好了,我的vs2013的环境是配置好了的。将生成的dll文件拷贝至jdk下jre的bin目录,其他目录也是可以的。

5)在服务器调用
在服务器中调用之前,我先试了下在java application中能否运行,和前面的简单示例一样的方法。
在其中遇到了一个脑残的问题,我用imread读取图像一直读取不到,返回值为0,当时心里慌呀,认为该不会是java和c++的数据的问题不能直接用C++的函数读取而是要java读取图片然后传到C++程序中进行图像处理吧。后来发现问题在于我vs是debug模式下,但是在配置oencv时没有改过来,用的还是release的lib。此时从编程到生成解决方案,C++都不提个醒。

在tomcat调用依旧是将dll放在jdk下jre的bin目录,没有另外将路径添加到native library location中。在public void doPost(HttpServletRequest request, HttpServletResponse response)方法中,拿到安卓客户端传来的图片后就调用c++方法,如下的grainCut函数。

//对上传的图片进行分割
	public static int grainCut(String srcPath){
		int total = GrainCutDll.imageProcess(srcPath);
		return total;
	} 

打开server,用手机app上传图像,得到结果:

    

总结:

在服务器调用C++程序时,遇到一个问题:客户端发出请求,本来在服务器的函数里面是要返回路径和分割计数的,但是调试时发现运行到调用c++程序那块代码时,直接跳过了,没有报出错信息,也没有异常抛出,最后还上传了图片并返回了路径。百思不得其解。

我后面将本地lib路径添加到native library location后,加载dll,才能够加载dll。最后我还是把native library location去掉了,直接把dll放在jre的bin下面实现的。

另外啰嗦几句,无法加载library和调用不了本地方法是最常见的错误,一般是考虑路径和生成的.h文件,dll文件的问题。

加载绝对路径下的dll:

System.load("D:/Program Files/vs2010project/graduation_project/GrainCutDll/x64/DebugGrainCutDll.dll");

输出dll可以放的位置,一般是jdk的bin,jdk下jre的bin,Tomcat的话就是tomcat的bin,还有说startup.bat所在的目录

System.out.println( System.getProperty("java.library.path") );

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,以下是基于 Unreal Engine 4.26 的 C++ 插件项目示例代码,用于在 Android 平台上调用 Android 原生 WebView 并加载网页: 首先,在您的插件项目中,您需要创建一个名为“WebViewPlugin”的 C++ 类。该类将包含所有与 WebView 相关的代码。以下是 WebViewPlugin.h 文件的示例代码: ```cpp #pragma once #include "CoreMinimal.h" #include "Modules/ModuleManager.h" class FWebViewPluginModule : public IModuleInterface { public: static inline FWebViewPluginModule& Get() { return FModuleManager::LoadModuleChecked<FWebViewPluginModule>("WebViewPlugin"); } static inline bool IsAvailable() { return FModuleManager::Get().IsModuleLoaded("WebViewPlugin"); } virtual void StartupModule() override; virtual void ShutdownModule() override; }; ``` 接下来,在 WebViewPlugin.cpp 文件中,您需要实现 StartupModule() 和 ShutdownModule() 函数,并在 StartupModule() 函数中初始化 WebView。以下是示例代码: ```cpp #include "WebViewPlugin.h" #include "Modules/ModuleManager.h" #include "PlatformWebView.h" void FWebViewPluginModule::StartupModule() { TSharedPtr<IPlatformWebView> PlatformWebView = FPlatformWebViewModule::Get().CreatePlatformWebView(); if (PlatformWebView.IsValid()) { PlatformWebView->Initialize(); PlatformWebView->LoadURL("https://www.example.com"); } } void FWebViewPluginModule::ShutdownModule() { TSharedPtr<IPlatformWebView> PlatformWebView = FPlatformWebViewModule::Get().GetPlatformWebView(); if (PlatformWebView.IsValid()) { PlatformWebView->CloseWindow(); } } IMPLEMENT_MODULE(FWebViewPluginModule, WebViewPlugin) ``` 在上面的示例代码中,我们使用 FPlatformWebViewModule 类来创建和初始化 WebView。该类是一个抽象类,它定义了与平台无关的接口,您可以使用它来访问特定平台的 WebView。 在 Android 平台上,您需要实现 IPlatformWebView 接口,并使用 JNI 调用 Android 原生 WebView。以下是 PlatformWebViewAndroid.h 和 PlatformWebViewAndroid.cpp 文件的示例代码: PlatformWebViewAndroid.h: ```cpp #pragma once #include "CoreMinimal.h" #include "PlatformWebView.h" class FPlatformWebViewAndroid : public IPlatformWebView { public: virtual void Initialize() override; virtual void LoadURL(const FString& URL) override; virtual void CloseWindow() override; }; ``` PlatformWebViewAndroid.cpp: ```cpp #include "PlatformWebViewAndroid.h" #include "Android/AndroidApplication.h" #include "Android/AndroidJNI.h" #include "Android/AndroidJava.h" void FPlatformWebViewAndroid::Initialize() { JNIEnv* Env = FAndroidApplication::GetJavaEnv(); if (Env) { FJavaClassObject WebViewClass(Env, FJavaWrapper::GameActivityClassID, FJavaWrapper::GameActivityThis); if (WebViewClass) { FJavaObjectMethod Method(Env, WebViewClass, "initializeWebView", "()V"); if (Method) { Method.Call(); } } } } void FPlatformWebViewAndroid::LoadURL(const FString& URL) { JNIEnv* Env = FAndroidApplication::GetJavaEnv(); if (Env) { jstring JURL = Env->NewStringUTF(TCHAR_TO_UTF8(*URL)); if (JURL) { FJavaClassObject WebViewClass(Env, FJavaWrapper::GameActivityClassID, FJavaWrapper::GameActivityThis); if (WebViewClass) { FJavaObjectMethod Method(Env, WebViewClass, "loadURL", "(Ljava/lang/String;)V"); if (Method) { Method.Call(JURL); } } Env->DeleteLocalRef(JURL); } } } void FPlatformWebViewAndroid::CloseWindow() { JNIEnv* Env = FAndroidApplication::GetJavaEnv(); if (Env) { FJavaClassObject WebViewClass(Env, FJavaWrapper::GameActivityClassID, FJavaWrapper::GameActivityThis); if (WebViewClass) { FJavaObjectMethod Method(Env, WebViewClass, "closeWebView", "()V"); if (Method) { Method.Call(); } } } } ``` 在上面的示例代码中,我们使用 FJavaClassObject 和 FJavaObjectMethod 类来调用 Android 原生 WebView。这些类是 Unreal Engine 中的封装类,它们可以简化 JNI 调用。 最后,在您的插件项目中,您需要添加 AndroidManifest.xml 文件,并在其中添加必要的权限和配置项。以下是示例代码: ```xml <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.YourCompany.WebViewPlugin" android:versionCode="1" android:versionName="1.0" > <uses-permission android:name="android.permission.INTERNET" /> <uses-feature android:name="android.hardware.touchscreen" android:required="false" /> <application android:label="@string/app_name" android:icon="@drawable/icon"> <activity android:name="com.epicgames.ue4.GameActivity" android:label="@string/app_name" android:launchMode="singleTask" android:screenOrientation="landscape" android:configChanges="keyboardHidden|orientation|screenSize"> <meta-data android:name="android.app.lib_name" android:value="WebViewPlugin" /> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest> ``` 在上面的示例代码中,我们添加了 INTERNET 权限和一个活动标记,以便在 AndroidManifest.xml 文件中注册插件活动。 希望这个示例代码能够帮助您实现在 Unreal Engine 4 中调用 Android 原生 WebView 并加载网页的功能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值