Native android ext and .so

"The topic of .so files has come up many times, and I need to ask about it again. I’m not very familiar with them, so I have a question: how do I add a .so library in an Android build?
No matter how I try, I can’t access the methods from the .so file.
Also, wherever I add it to the .apk, ‘_test.so’ is appended to the file name.
unpacked aar


apk

NE structure

cmake from sdl example
CMakeLists.txt (6.3 KB)

A shared object file is loaded and used at runtime by the main application. You usually include .so files in your final application bundle from a Gradle dependency with an .aar file containing .so files:

When you bundle for Android and you have a dependency which includes a /jni folder with .so files we get them from the build server and include them in your .aab/.apk file. In .aab files the .so files are stored in /base/lib/PLATFORM/foobar.so:

You should be able to manually include .so files like you did by putting them in your extension in /res/android …

Although this looks a bit odd:

Screenshot 2024-08-22 at 23.13.00

Shouldn’t it be:

/res/arm64-android/lib/arm64-v8a/libgadsme.so

1 Like

yes! now it builds, and i can operate with code from Java side, but if i try to call same methods from C++, i got error

2024-08-27 12:37:12.762  7166-7204  om.example.todo         com.example.todo                     A  java_vm_ext.cc:591] JNI DETECTED ERROR IN APPLICATION: JNI NewGlobalRef called with pending exception java.lang.ClassNotFoundException: Didn't find class "gadsme.support.resource.Resource" on path: DexPathList[[directory "."],nativeLibraryDirectories=[/system/lib64, /system_ext/lib64, /system/lib64, /system_ext/lib64]]
                                                                                                    java_vm_ext.cc:591]   at java.lang.Class dalvik.system.BaseDexClassLoader.findClass(java.lang.String) (BaseDexClassLoader.java:259)
                                                                                                    java_vm_ext.cc:591]   at java.lang.Class java.lang.ClassLoader.loadClass(java.lang.String, boolean) (ClassLoader.java:379)
                                                                                                    java_vm_ext.cc:591]   at java.lang.Class java.lang.ClassLoader.loadClass(java.lang.String) (ClassLoader.java:312)
                                                                                                    java_vm_ext.cc:591] 
                                                                                                    java_vm_ext.cc:591]     in call to NewGlobalRef

but class gadsme.support.resource.Resource is already in dex file

also i don’t understand why i got two files _test.so and .so of lib

Me neither, that looks very strange

Can you share a bit of code how you set this up?

My cpp file:

#define EXTENSION_NAME DefGadsmeSDK
#define LIB_NAME "DefGadsmeSDK"
#define MODULE_NAME "def_gadsme_sdk"
#define DLIB_LOG_DOMAIN LIB_NAME

#include <dmsdk/sdk.h>
#include "def_gadsme_sdk.h"

#include <cmath>
#include <iostream>

// Import the SDK header on other platforms

#include "GadsmeSDK.h"

using namespace gadsme;

namespace dmGadsmeSDK {
static std::string str = "my_key";

static void set_sandbox(bool value) {
    // Gadsme_setForceSandbox(true);
}

static const luaL_reg Module_methods[] =
{
    {0, 0}
};

static void LuaInit(lua_State* L)
{
    int top = lua_gettop(L);
    luaL_register(L, MODULE_NAME, Module_methods);
    lua_pop(L, 1);
    assert(top == lua_gettop(L));
}

dmExtension::Result InitializeDefGadsmeSDK(dmExtension::Params* params)
{
    LuaInit(params->m_L);
    dmLogInfo("Registered extension DefGadsmeSDK");
    Initialize_Ext();
    ////Delayed CRASH after calling Gadsme_setGameId        
    Gadsme_setGameId(Gadsme_str(str));
    set_sandbox(true);
    // Gadsme_init();

   
    return dmExtension::RESULT_OK;
}


DM_DECLARE_EXTENSION(EXTENSION_NAME, LIB_NAME, 0, 0, InitializeDefGadsmeSDK, 0, 0, 0)
    
} //namespace

Part of GadsmeSDK.h

#define GADSME_SDK_H

#include <string>
#include <memory>
#include <functional>
#include <vector>
#include <map>
#include <utility>

#if defined(__ANDROID__)
    #define GADSME_ANDROID 1
#elif defined(_WIN32)
    #define GADSME_WINDOWS 1
#elif defined(__APPLE__)
    #include <TargetConditionals.h>
    #if TARGET_OS_IPHONE
        #define GADSME_IOS 1
    #else
        #define GADSME_MAC 1
    #endif
#endif

#if GADSME_ANDROID
#include <jni.h>
#endif

#if defined _WIN32 || defined __CYGWIN__
  #ifdef BUILDING_GADSME
    #ifdef __GNUC__
      #define GADSME_PUBLIC __attribute__ ((dllexport))
    #else
      #define GADSME_PUBLIC __declspec(dllexport)
    #endif
  #else
    #ifdef __GNUC__
      #define GADSME_PUBLIC __attribute__ ((dllimport))
    #else
      #define GADSME_PUBLIC __declspec(dllimport)
    #endif
  #endif
  #define GADSME_HIDDEN
#else
  #if __GNUC__ >= 4
    #define GADSME_PUBLIC __attribute__ ((visibility ("default")))
    #define GADSME_HIDDEN __attribute__ ((visibility ("hidden")))
  #else
    #define GADSME_PUBLIC
    #define GADSME_HIDDEN
  #endif
#endif

/**
 * Gadsme SDK namespace.
 *
 * The SDK can be initialized from any thread, but any following call
 * should be done from this same thread. Calling from another thread will
 * cause a crash, unless using a method which is explicitly documented as
 * being thread safe, and thus can be called from any thread without issues.
 */
namespace gadsme {

/// Type aliases

    #if defined(_MSC_VER) && _MSC_VER < 1900

    typedef std::shared_ptr< std::vector<unsigned char> > Gadsme_Bytes;

    typedef std::shared_ptr<std::string> Gadsme_String;

    typedef std::shared_ptr< std::map< std::string, gadsme::Gadsme_String> > Gadsme_StringStringMap;

    typedef std::shared_ptr< std::vector<int> > Gadsme_IntArray;

    #else

    using Gadsme_Bytes = std::shared_ptr< std::vector<unsigned char> >;

    using Gadsme_String = std::shared_ptr<std::string>;

    using Gadsme_StringStringMap = std::shared_ptr< std::map< std::string, gadsme::Gadsme_String> >;

    using Gadsme_IntArray = std::shared_ptr< std::vector<int> >;

    #endif

    ...............................................

    GADSME_PUBLIC Gadsme_String Gadsme_str(std::string str);

    ...............................................
   
    GADSME_PUBLIC void Gadsme_setGameId(Gadsme_String gameId);

    ...............................................
}

ext.manifest

name: "DefGadsmeSDK"

platforms:
    armv7-android:
      context:
        defines: ['__ANDROID__']
    arm64-android:
      context:
        defines: ['__ANDROID__']

I’m pretty sure this is unnecessary.

So you are able to call the function in the library? But it crashes after a while? I’m curious to learn what the Android device log says. Have you looked for clues as to why it crashes?

1 Like

got this error:

textava_vm_ext.cc:591] JNI DETECTED ERROR IN APPLICATION: JNI NewGlobalRef called with pending exception java.lang.ClassNotFoundException: Didn't find class "gadsme.support.resource.Resource" on path: DexPathList[[directory "."],nativeLibraryDirectories=[/system/lib64, /system_ext/lib64, /system/lib64, /system_ext/lib64]]
java_vm_ext.cc:591]   at java.lang.Class dalvik.system.BaseDexClassLoader.findClass(java.lang.String) (BaseDexClassLoader.java:259)
java_vm_ext.cc:591]   at java.lang.Class java.lang.ClassLoader.loadClass(java.lang.String, boolean) (ClassLoader.java:379)    
java_vm_ext.cc:591]   at java.lang.Class java.lang.ClassLoader.loadClass(java.lang.String) (ClassLoader.java:312)
java_vm_ext.cc:591] 
java_vm_ext.cc:591]     in call to NewGlobalRef