在非Xamarin/Mono的Java Android项目中调用C# DLL的技术问询
在Android Java项目中调用C# DLL的解决方案与疑问解答
先明确你的场景:你想在纯Java开发的Android项目里调用C# DLL,最初的方案是用DllExport把C#转成C可调用的DLL再打包成.so,但遇到了C代码依赖windows.h的问题,下面针对你的两个疑问逐一拆解:
疑问1:如何不依赖windows.h来使用DllExport生成的DLL?
DllExport生成的是标准C兼容的导出函数,并非只能在Windows环境下使用。Android基于Linux内核,我们可以用POSIX标准的动态链接库操作函数替代Windows的LoadLibrary和GetProcAddress——这些函数定义在dlfcn.h头文件里,完全不需要windows.h。
修改后的Android兼容C++调用代码
#include <dlfcn.h> #include <iostream> // 定义与C#导出函数匹配的函数指针类型 typedef int(*GetRandomEvenNumber)(); int main() { // 加载Android平台的动态库(注意路径是.so文件,比如./libmycsharp.so) void* lib = dlopen("libmycsharp.so", RTLD_LAZY); if (!lib) { std::cerr << "无法加载库: " << dlerror() << std::endl; return 1; } // 获取导出函数的地址 dlerror(); // 清除之前的错误状态 GetRandomEvenNumber getRndNumber = (GetRandomEvenNumber)dlsym(lib, "GetRandomEvenNumber"); const char* err = dlerror(); if (err) { std::cerr << "无法找到函数: " << err << std::endl; dlclose(lib); return 1; } // 调用C#导出的函数 int c = getRndNumber(); std::cout << "生成的随机偶数: " << c << std::endl; // 释放动态库资源 dlclose(lib); return 0; }
编译注意事项
编译这段代码时,需要链接POSIX动态链接库,添加-ldl参数,比如:
g++ -o test_csharp_call test_csharp_call.cpp -ldl
另外,你需要把DllExport生成的DLL交叉编译成对应Android架构的.so文件(比如armeabi-v7a、arm64-v8a),确保和你的Android项目架构匹配。
疑问2:是否可以使用.NET Core 2.0来实现该需求而无需使用DllExport?
很遗憾,.NET Core 2.0无法直接满足这个需求,原因有两点:
- .NET Core 2.0的核心支持平台是Windows、Linux桌面和服务器,对Android的原生支持几乎为零,没有官方工具链能把它的代码编译成Android可调用的
.so库。 - .NET Core 2.0没有类似
[UnmanagedCallersOnly]的特性(该特性在.NET 5+引入),无法直接导出可被原生代码调用的函数,仍然需要依赖DllExport这类第三方工具生成兼容的导出符号。
更优替代方案(升级.NET版本)
如果可以升级到.NET 6及以上的版本(比如用.NET for Android),你完全可以抛弃DllExport:
- 在.NET项目中用
[UnmanagedCallersOnly(EntryPoint = "GetRandomEvenNumber")]标记要导出的静态函数,替代DllExport。 - 通过.NET的AOT编译功能,直接将C#代码编译成Android对应的
.so原生库。 - 最后在Android的C层(JNI)调用这个
.so的导出函数,再让Java层通过JNI调用C代码。
举个修改后的C#代码示例(.NET 6+):
namespace NumbersLibCS { public static class Math { [UnmanagedCallersOnly(EntryPoint = "GetRandomEvenNumber")] public static int GetRandomEvenNumber() { var rnd = new Random(); int n = rnd.Next(1, 1000 ) * 2; return n; } } }
然后用.NET发布命令编译成Android原生库:
dotnet publish -r android-arm64 -c Release
这样生成的.so库可以直接被Android的C++代码调用,无需额外的包装层。
内容的提问来源于stack exchange,提问作者S.A.Parkhid
相关产品推荐
相关产品推荐

