diff --git a/CMakeLists.txt b/CMakeLists.txt index 345654850..f06ac5655 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -96,18 +96,9 @@ if(SFML_OS_ANDROID) # we install libs in a subdirectory named after the ABI set(CMAKE_INSTALL_LIBDIR "${CMAKE_INSTALL_LIBDIR}/${CMAKE_ANDROID_ARCH_ABI}") - # pass shared STL configuration (if any) - if(CMAKE_ANDROID_STL_TYPE MATCHES "_shared") - add_definitions("-DSTL_LIBRARY=${CMAKE_ANDROID_STL_TYPE}") - endif() # let the user switch ABIs set(ANDROID_ABI "armeabi-v7a" CACHE STRING "Look at the NDK docs for currently supported ABIs") - - # this is a workaround to compile sfml-activity without the stl library as a dependency - # we save the original compilation command line to restore it later in Macro.cmake - set(CMAKE_CXX_CREATE_SHARED_LIBRARY_WITH_STL ${CMAKE_CXX_CREATE_SHARED_LIBRARY}) - set(CMAKE_CXX_CREATE_SHARED_LIBRARY_WITHOUT_STL " -o ") endif() # Install directories diff --git a/cmake/Macros.cmake b/cmake/Macros.cmake index 8ce8edbc8..7cf895f42 100644 --- a/cmake/Macros.cmake +++ b/cmake/Macros.cmake @@ -212,18 +212,6 @@ macro(sfml_add_library module) sfml_set_common_ios_properties(${target}) endif() - # sfml-activity library is our bootstrap activity and must not depend on stlport_shared - # (otherwise Android will fail to load it) - if(SFML_OS_ANDROID) - if(${target} MATCHES "sfml-activity") - set_target_properties(${target} PROPERTIES COMPILE_FLAGS -fpermissive) - set_target_properties(${target} PROPERTIES LINK_FLAGS "-landroid -llog") - set(CMAKE_CXX_CREATE_SHARED_LIBRARY ${CMAKE_CXX_CREATE_SHARED_LIBRARY_WITHOUT_STL}) - else() - set(CMAKE_CXX_CREATE_SHARED_LIBRARY ${CMAKE_CXX_CREATE_SHARED_LIBRARY_WITH_STL}) - endif() - endif() - # add the install rule install(TARGETS ${target} EXPORT SFMLConfigExport RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT bin diff --git a/examples/android/app/src/main/AndroidManifest.xml b/examples/android/app/src/main/AndroidManifest.xml index 851f4b16e..7a69cda5d 100644 --- a/examples/android/app/src/main/AndroidManifest.xml +++ b/examples/android/app/src/main/AndroidManifest.xml @@ -16,8 +16,7 @@ android:configChanges="keyboardHidden|orientation|screenSize" android:exported="true"> - - + diff --git a/examples/android/app/src/main/jni/CMakeLists.txt b/examples/android/app/src/main/jni/CMakeLists.txt index 3018024f1..e93995dee 100644 --- a/examples/android/app/src/main/jni/CMakeLists.txt +++ b/examples/android/app/src/main/jni/CMakeLists.txt @@ -6,20 +6,14 @@ set(SFML_DIR "${CMAKE_ANDROID_NDK}/sources/third_party/sfml/lib/${CMAKE_ANDROID_ # Create the libsfml-example.so library that contains the application's c++ code add_library(sfml-example SHARED main.cpp) -# Find and link SFML. -# We must link to the network and audio components even if we don't use them, because sfml-activity will try to load them +# Find and link SFML find_package(SFML 3 REQUIRED COMPONENTS Graphics Audio Network) -target_link_libraries(sfml-example PRIVATE SFML::Graphics SFML::Audio SFML::Network SFML::Activity android log) +target_link_libraries(sfml-example PRIVATE SFML::Graphics android log) # The ANativeActivity_onCreate function from SFML::Main needs to be exposed in -# our libsfml-example.so file so that is can be loaded at runtime by sfml-activity. +# our libsfml-example.so file so that is can be loaded at runtime. target_link_libraries(sfml-example PUBLIC -Wl,--whole-archive SFML::Main -Wl,--no-whole-archive ) - -# We need to manually copy the OpenAL library into the apk, even if we don't use it, because sfml-activity will try to load it -add_library(OpenAL::OpenAL SHARED IMPORTED) -set_target_properties(OpenAL::OpenAL PROPERTIES IMPORTED_LOCATION "${CMAKE_ANDROID_NDK}/sources/third_party/sfml/extlibs/lib/${CMAKE_ANDROID_ARCH_ABI}/libopenal.so") -target_link_libraries(sfml-example PRIVATE OpenAL::OpenAL) diff --git a/src/SFML/CMakeLists.txt b/src/SFML/CMakeLists.txt index 6a8952cb0..126a825cb 100644 --- a/src/SFML/CMakeLists.txt +++ b/src/SFML/CMakeLists.txt @@ -42,7 +42,7 @@ set(LIBRARY_OUTPUT_PATH "${PROJECT_BINARY_DIR}/lib") # sfml-system add_subdirectory(System) -# sfml-main and sfml-activity +# sfml-main if(SFML_OS_WINDOWS OR SFML_OS_ANDROID OR SFML_OS_IOS) add_subdirectory(Main) endif() diff --git a/src/SFML/Main/CMakeLists.txt b/src/SFML/Main/CMakeLists.txt index da5a7d827..580027369 100644 --- a/src/SFML/Main/CMakeLists.txt +++ b/src/SFML/Main/CMakeLists.txt @@ -31,10 +31,3 @@ set_target_properties(sfml-main PROPERTIES RELEASE_POSTFIX "" MINSIZEREL_POSTFIX "" RELWITHDEBINFO_POSTFIX "") - -# because of a current limitation on Android (which prevents one library -# from depending on shared libraries), we need a bootstrap activity which -# will load our shared libraries manually -if(SFML_OS_ANDROID) - sfml_add_library(Activity SOURCES ${SRCROOT}/SFMLActivity.cpp) -endif() diff --git a/src/SFML/Main/SFMLActivity.cpp b/src/SFML/Main/SFMLActivity.cpp deleted file mode 100644 index c97e2710f..000000000 --- a/src/SFML/Main/SFMLActivity.cpp +++ /dev/null @@ -1,221 +0,0 @@ -//////////////////////////////////////////////////////////// -// -// SFML - Simple and Fast Multimedia Library -// Copyright (C) 2013 Jonathan De Wachter (dewachter.jonathan@gmail.com) -// -// This software is provided 'as-is', without any express or implied warranty. -// In no event will the authors be held liable for any damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it freely, -// subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; -// you must not claim that you wrote the original software. -// If you use this software in a product, an acknowledgment -// in the product documentation would be appreciated but is not required. -// -// 2. Altered source versions must be plainly marked as such, -// and must not be misrepresented as being the original software. -// -// 3. This notice may not be removed or altered from any source distribution. -// -//////////////////////////////////////////////////////////// - -#include - -#include -#include -#include - -#include -#include - -#include -#include -#include - -#define LOGE(...) ((void)__android_log_print(ANDROID_LOG_INFO, "sfml-activity", __VA_ARGS__)) - -namespace -{ -using activityOnCreatePointer = void (*)(ANativeActivity*, void*, std::size_t); -} - -const char* getLibraryName(JNIEnv* lJNIEnv, jobject& objectActivityInfo) -{ - // This function reads the value of meta-data "sfml.app.lib_name" - // found in the Android Manifest file and returns it. It performs the - // following Java code using the JNI interface: - // - // ai.metaData.getString("sfml.app.lib_name"); - static char name[256]; - - // Get metaData instance from the ActivityInfo object - jclass classActivityInfo = lJNIEnv->FindClass("android/content/pm/ActivityInfo"); - jfieldID fieldMetaData = lJNIEnv->GetFieldID(classActivityInfo, "metaData", "Landroid/os/Bundle;"); - jobject objectMetaData = lJNIEnv->GetObjectField(objectActivityInfo, fieldMetaData); - - // Create a java string object containing "sfml.app.lib_name" - jobject objectName = lJNIEnv->NewStringUTF("sfml.app.lib_name"); - - // Get the value of meta-data named "sfml.app.lib_name" - jclass classBundle = lJNIEnv->FindClass("android/os/Bundle"); - jmethodID methodGetString = lJNIEnv->GetMethodID(classBundle, "getString", "(Ljava/lang/String;)Ljava/lang/String;"); - auto* valueString = static_cast(lJNIEnv->CallObjectMethod(objectMetaData, methodGetString, objectName)); - - // No meta-data "sfml.app.lib_name" was found so we abort and inform the user - if (valueString == nullptr) - { - LOGE("No meta-data 'sfml.app.lib_name' found in AndroidManifest.xml file"); - std::exit(1); - } - - // Convert the application name to a C++ string and return it - const auto applicationNameLength = static_cast(lJNIEnv->GetStringUTFLength(valueString)); - const char* applicationName = lJNIEnv->GetStringUTFChars(valueString, nullptr); - - if (applicationNameLength >= 256) - { - LOGE("The value of 'sfml.app.lib_name' must not be longer than 255 characters."); - std::exit(1); - } - - strncpy(name, applicationName, static_cast(applicationNameLength)); - name[applicationNameLength] = '\0'; - lJNIEnv->ReleaseStringUTFChars(valueString, applicationName); - - return name; -} - -void* loadLibrary(const char* libraryName, JNIEnv* lJNIEnv, jobject& objectActivityInfo) -{ - // Find out the absolute path of the library - jclass classActivityInfo = lJNIEnv->FindClass("android/content/pm/ActivityInfo"); - jfieldID fieldApplicationInfo = lJNIEnv->GetFieldID(classActivityInfo, - "applicationInfo", - "Landroid/content/pm/ApplicationInfo;"); - jobject objectApplicationInfo = lJNIEnv->GetObjectField(objectActivityInfo, fieldApplicationInfo); - - jclass classApplicationInfo = lJNIEnv->FindClass("android/content/pm/ApplicationInfo"); - jfieldID fieldNativeLibraryDir = lJNIEnv->GetFieldID(classApplicationInfo, "nativeLibraryDir", "Ljava/lang/String;"); - - jobject objectDirPath = lJNIEnv->GetObjectField(objectApplicationInfo, fieldNativeLibraryDir); - - jclass classSystem = lJNIEnv->FindClass("java/lang/System"); - jmethodID staticMethodMapLibraryName = lJNIEnv->GetStaticMethodID(classSystem, - "mapLibraryName", - "(Ljava/lang/String;)Ljava/lang/String;"); - - jstring libNameObject = lJNIEnv->NewStringUTF(libraryName); - jobject objectName = lJNIEnv->CallStaticObjectMethod(classSystem, staticMethodMapLibraryName, libNameObject); - - jclass classFile = lJNIEnv->FindClass("java/io/File"); - jmethodID fileConstructor = lJNIEnv->GetMethodID(classFile, "", "(Ljava/lang/String;Ljava/lang/String;)V"); - jobject objectFile = lJNIEnv->NewObject(classFile, fileConstructor, objectDirPath, objectName); - - // Get the library absolute path and convert it - jmethodID methodGetPath = lJNIEnv->GetMethodID(classFile, "getPath", "()Ljava/lang/String;"); - auto* javaLibraryPath = static_cast(lJNIEnv->CallObjectMethod(objectFile, methodGetPath)); - const char* libraryPath = lJNIEnv->GetStringUTFChars(javaLibraryPath, nullptr); - - // Manually load the library - void* handle = dlopen(libraryPath, RTLD_NOW | RTLD_GLOBAL); - if (!handle) - { - LOGE("dlopen(\"%s\"): %s", libraryPath, dlerror()); - std::exit(1); - } - - // Release the Java string - lJNIEnv->ReleaseStringUTFChars(javaLibraryPath, libraryPath); - - return handle; -} - -JNIEXPORT void ANativeActivity_onCreate(ANativeActivity* activity, void* savedState, std::size_t savedStateSize) -{ - // Before we can load a library, we need to find out its location. As - // we're powerless here in C/C++, we need the JNI interface to communicate - // with the attached Java virtual machine and perform some Java calls in - // order to retrieve the absolute path of our libraries. - // - // Here's the snippet of Java code it performs: - // -------------------------------------------- - // ai = getPackageManager().getActivityInfo(getIntent().getComponent(), PackageManager.GET_META_DATA); - // File libraryFile = new File(ai.applicationInfo.nativeLibraryDir, System.mapLibraryName(libname)); - // String path = libraryFile.getPath(); - // - // With libname being the library name such as "jpeg". - - // Retrieve JNI environment and JVM instance - JNIEnv* lJNIEnv = activity->env; - - // Retrieve the NativeActivity - jobject objectNativeActivity = activity->clazz; - jclass classNativeActivity = lJNIEnv->GetObjectClass(objectNativeActivity); - - // Retrieve the ActivityInfo - jmethodID methodGetPackageManager = lJNIEnv->GetMethodID(classNativeActivity, - "getPackageManager", - "()Landroid/content/pm/PackageManager;"); - jobject objectPackageManager = lJNIEnv->CallObjectMethod(objectNativeActivity, methodGetPackageManager); - - jmethodID methodGetIndent = lJNIEnv->GetMethodID(classNativeActivity, "getIntent", "()Landroid/content/Intent;"); - jobject objectIntent = lJNIEnv->CallObjectMethod(objectNativeActivity, methodGetIndent); - - jclass classIntent = lJNIEnv->FindClass("android/content/Intent"); - jmethodID methodGetComponent = lJNIEnv->GetMethodID(classIntent, - "getComponent", - "()Landroid/content/ComponentName;"); - - jobject objectComponentName = lJNIEnv->CallObjectMethod(objectIntent, methodGetComponent); - - jclass classPackageManager = lJNIEnv->FindClass("android/content/pm/PackageManager"); - - jfieldID fieldGetMetaData = lJNIEnv->GetStaticFieldID(classPackageManager, "GET_META_DATA", "I"); - jint getMetaData = lJNIEnv->GetStaticIntField(classPackageManager, fieldGetMetaData); - - jmethodID methodGetActivityInfo = lJNIEnv->GetMethodID(classPackageManager, - "getActivityInfo", - "(Landroid/content/ComponentName;I)Landroid/content/pm/" - "ActivityInfo;"); - jobject objectActivityInfo = lJNIEnv->CallObjectMethod(objectPackageManager, methodGetActivityInfo, objectComponentName, getMetaData); - - // Load our libraries in reverse order -#if defined(STL_LIBRARY) -#define SFML_QS(s) SFML_S(s) -#define SFML_S(s) #s - loadLibrary(SFML_QS(STL_LIBRARY), lJNIEnv, objectActivityInfo); -#undef SFML_S -#undef SFML_QS -#endif - loadLibrary("openal", lJNIEnv, objectActivityInfo); - -#if !defined(SFML_DEBUG) - loadLibrary("sfml-system", lJNIEnv, objectActivityInfo); - loadLibrary("sfml-window", lJNIEnv, objectActivityInfo); - loadLibrary("sfml-graphics", lJNIEnv, objectActivityInfo); - loadLibrary("sfml-audio", lJNIEnv, objectActivityInfo); - loadLibrary("sfml-network", lJNIEnv, objectActivityInfo); -#else - loadLibrary("sfml-system-d", lJNIEnv, objectActivityInfo); - loadLibrary("sfml-window-d", lJNIEnv, objectActivityInfo); - loadLibrary("sfml-graphics-d", lJNIEnv, objectActivityInfo); - loadLibrary("sfml-audio-d", lJNIEnv, objectActivityInfo); - loadLibrary("sfml-network-d", lJNIEnv, objectActivityInfo); -#endif - - void* handle = loadLibrary(getLibraryName(lJNIEnv, objectActivityInfo), lJNIEnv, objectActivityInfo); - - // Call the original ANativeActivity_onCreate function - auto nativeActivityOnCreate = reinterpret_cast(dlsym(handle, "ANativeActivity_onCreate")); - - if (!nativeActivityOnCreate) - { - LOGE("sfml-activity: Undefined symbol ANativeActivity_onCreate"); - std::exit(1); - } - - nativeActivityOnCreate(activity, savedState, savedStateSize); -}