How to add a shared library (.so) in android project
Author Syntopia. Thanks to Chris Babcock for the info. For example, to add support for OpenSSL. The latest compiled version of the library you can find in github (or compiled by hand), take this fo...
Author Syntopia. Thanks to Chris Babcock for the info.
For example, to add support for OpenSSL.
The latest compiled version of the library you can find in github (or compiled by hand), take this for example:
openssl-1.0.2j
Select the desired architecture, for this example we will take "arch-armeabi-v7a". After downloading, create a folder "/armv7" in the source folder "C:\Users\Vadim\Documents\Unreal Projects\AndroidOpenSSL\Source\AndroidOpenSSL" in my case. And move the "libcrypto.so" there in "armv7". Next open the file .Build.cs it should look something like this, here I just add the library to work with OpenSSL in the Windows.
Headers are in "AndroidOpenSSL/ThirdParty/OpenSSL/Includes" connect them like this:
string IncludesPath = Path.Combine(ThirdPartyPath, "OpenSSL", "Includes");
PublicIncludePaths.Add(IncludesPath);
For android target set the path to the library and APL (AndroidPluginLanguage).
using UnrealBuildTool;
using System.IO;
using System; //Console.WriteLine("");
public class AndroidOpenSSL : ModuleRules
{
private string ModulePath
{
get { return ModuleDirectory; }
}
private string ThirdPartyPath
{
get { return Path.GetFullPath(Path.Combine(ModulePath, "../../ThirdParty/")); }
}
public AndroidOpenSSL(TargetInfo Target)
{
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore" });
PrivateDependencyModuleNames.AddRange(new string[] { });
string IncludesPath = Path.Combine(ThirdPartyPath, "OpenSSL", "Includes");
PublicIncludePaths.Add(IncludesPath);
if ((Target.Platform == UnrealTargetPlatform.Win64)
(Target.Platform == UnrealTargetPlatform.Win32))
{
string LibrariesPath = Path.Combine(ThirdPartyPath, "OpenSSL", "Libraries");
PublicAdditionalLibraries.Add(Path.Combine(LibrariesPath, "libeay32.lib"));
PublicAdditionalLibraries.Add(Path.Combine(LibrariesPath, "ssleay32.lib"));
}
if (Target.Platform == UnrealTargetPlatform.Android)
{
string BuildPath = Utils.MakePathRelativeTo(ModuleDirectory, BuildConfiguration.RelativeEnginePath);
AdditionalPropertiesForReceipt.Add(new ReceiptProperty("AndroidPlugin", Path.Combine(BuildPath, "My_APL_armv7.xml")));
PublicAdditionalLibraries.Add(BuildPath + "/armv7/libcrypto.so");
}
}
}
Create in the same place file "My_APL_armv7.xml". A great example can be found here:
The contents will look like this:
That's all you can packing. If everything is fine, we'll see it in the log:
UATHelper: Packaging (Android (ETC2)): UnrealBuildTool: File C:\Users\Vadim\Documents\Unreal Projects\AndroidOpenSSL\Source\AndroidOpenSSL/armv7/libcrypto.so copied to C:\Users\Vadim\Documents\Unreal Projects\AndroidOpenSSL\Intermediate/Android/APK/libs/armeabi-v7a/libcrypto.so
Possible errors (for OpenSSL):
After installing the application on androyd I can not run it, looked into the logcat, there was such an error:
E/AndroidRuntime( 1574): java.lang.UnsatisfiedLinkError: dlopen failed: could not load library "libcrypto.so.1.0.0" needed by "libUE4.so"; caused by library "libcrypto.so.1.0.0" not found
If you rename the .apk to .zip open and go to the "\lib" you will see that there is not "libcrypto.so.1.0.0" only "libcrypto.so". Version number sewn somewhere in .so, a simple rename will not help. We need to recompile OpenSSL with the required flag, or change something in .so using rpl:
rpl -R -e .so.1.0.0 "_1_0_0.so" /path/to/libcrypto.so
More details in the answer:
An example of calculating the hash SHA256.
I created the HUD for this:
// OpenSSL tests
#include
#include
#include
void ADebugHUD::DrawHUD()
{
Super::DrawHUD();
FString hashTest = "Hash test (sha256): " + GetSHA256_s("Baron", strlen("Baron"));
DrawText(hashTest, FColor::White, 50, 50, HUDFont);
}
FString ADebugHUD::GetSHA256_s(const void * data, size_t data_len)
{
EVP_MD_CTX mdctx;
unsigned char md_value[EVP_MAX_MD_SIZE];
unsigned int md_len;
EVP_DigestInit(&mdctx, EVP_sha256());
EVP_DigestUpdate(&mdctx, data, (size_t)data_len);
EVP_DigestFinal_ex(&mdctx, md_value, &md_len);
EVP_MD_CTX_cleanup(&mdctx);
std::stringstream s;
s.fill('0');
for (size_t i = 0; i < md_len; ++i)
s < std::setw(2) < std::hex < (unsigned short)md_value[i];
return s.str().c_str();
}
Output: