diff --git a/CMakeLists.txt b/CMakeLists.txt index 5aa1a74..142a200 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,6 +3,11 @@ cmake_minimum_required(VERSION 3.25) project(swift-firebase LANGUAGES Swift) +if(ANDROID) + enable_language(C) + include(FindJava) + include(UseJava) +endif() set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) @@ -39,6 +44,10 @@ else() message(FATAL_ERROR "unsupported firebase-cpp-sdk platform") endif() +if(ANDROID) + add_subdirectory(Sources/FirebaseAndroid) +endif() + add_library(FirebaseCore SHARED Sources/FirebaseCore/FirebaseApp+Swift.swift Sources/FirebaseCore/FirebaseConfiguration.swift @@ -55,6 +64,10 @@ target_link_libraries(FirebaseCore PRIVATE firebase_app flatbuffers zlibstatic) +if(ANDROID) + target_link_libraries(FirebaseCore PRIVATE + FirebaseAndroidJNI) +endif() add_library(FirebaseAuth SHARED Sources/FirebaseAuth/AuthStateDidChangeListenerHandle.swift diff --git a/Sources/FirebaseAndroid/CMakeLists.txt b/Sources/FirebaseAndroid/CMakeLists.txt new file mode 100644 index 0000000..4fd4ff7 --- /dev/null +++ b/Sources/FirebaseAndroid/CMakeLists.txt @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: BSD-3-Clause + +add_library(FirebaseAndroidJNI SHARED + jni.c) +target_include_directories(FirebaseAndroidJNI PUBLIC + include) +target_link_libraries(FirebaseAndroidJNI PRIVATE + log) + diff --git a/Sources/FirebaseAndroid/abi.h b/Sources/FirebaseAndroid/abi.h new file mode 100644 index 0000000..f000efb --- /dev/null +++ b/Sources/FirebaseAndroid/abi.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + +#ifndef SwiftFirebase_FirebaseAndroidShim_abi_h +#define SwiftFirebase_FirebaseAndroidShim_abi_h + +#if defined(FirebaseAndroidJNI_EXPORTS) +#define FIREBASE_ANDROID_ABI __attribute__((__visibility__("default"))) +#else +#define FIREBASE_ANDROID_ABI __attribute__((__visibility__("default"))) +#endif + +#endif diff --git a/Sources/FirebaseAndroid/include/FirebaseAndroid.h b/Sources/FirebaseAndroid/include/FirebaseAndroid.h new file mode 100644 index 0000000..cdd09dd --- /dev/null +++ b/Sources/FirebaseAndroid/include/FirebaseAndroid.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + +#ifndef SwiftFirebase_FirebaseAndroidShim_FirebaseAndroid_h +#define SwiftFirebase_FirebaseAndroidShim_FirebaseAndroid_h + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +jobject SwiftFirebase_GetActivity(void); +JNIEnv *SwiftFirebase_GetJavaEnvironment(void); +JavaVM *SwiftFirebase_GetJVM(void); + +#if defined(__cplusplus) +} +#endif + +#endif diff --git a/Sources/FirebaseAndroid/include/module.modulemap b/Sources/FirebaseAndroid/include/module.modulemap new file mode 100644 index 0000000..4235dc3 --- /dev/null +++ b/Sources/FirebaseAndroid/include/module.modulemap @@ -0,0 +1,6 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + +module FirebaseAndroid { + header "FirebaseAndroid.h" + export * +} diff --git a/Sources/FirebaseAndroid/jni.c b/Sources/FirebaseAndroid/jni.c new file mode 100644 index 0000000..f7e75bd --- /dev/null +++ b/Sources/FirebaseAndroid/jni.c @@ -0,0 +1,79 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + +#include "FirebaseAndroid.h" +#include "abi.h" +#include "log.h" + +#include + +static JavaVM *g_VM; +static JNIEnv *g_Env; +static jobject *g_Activity; + +#define N_ELEMENTS(array) (sizeof((array)) / sizeof(*(array))) + +static const char kClassPath[] = "company/thebrowser/Native"; + +static jboolean +SwiftFirebase_RegisterActivity(JNIEnv *env, jobject *this, jobject *activity) +{ + assert(g_Activity == NULL && "re-registeration of activity"); + if (g_Activity) return JNI_FALSE; + + g_Activity = activity; + return JNI_TRUE; +} + +static JNINativeMethod kMethods[] = { + { "RegisterActivity", "()Z", SwiftFirebase_RegisterActivity }, +}; + +static void +RegisterNativeMethods(JNIEnv *env) +{ + jclass class; + jint result; + + class = (*env)->FindClass(env, kClassPath); + if (class == NULL) { + LOG_ERROR("unable to find class '%s'", kClassPath); + return; + } + LOG_DEBUG("located class path '%s': %p", kClassPath, class); + + result = (*env)->RegisterNatives(env, class, kMethods, N_ELEMENTS(kMethods)); + if (result < 0) { + LOG_ERROR("JVM.RegisterNatives(%s): %u", kClassPath, result); + return; + } + LOG_DEBUG("registered %u methods", N_ELEMENTS(kMethods)); +} + +FIREBASE_ANDROID_ABI +jint JNI_OnLoad(JavaVM *vm, void *reserved) +{ + g_VM = vm; + if ((*g_VM)->GetEnv(g_VM, (void **)&g_Env, JNI_VERSION_1_6) == JNI_OK) + return JNI_VERSION_1_6; + RegisterNativeMethods(g_Env); + return -1; +} + +FIREBASE_ANDROID_ABI +jobject SwiftFirebase_GetActivity(void) +{ + assert(g_Activity && "`GetActivity` invoked before `RegisterActivity`"); + return *g_Activity; +} + +FIREBASE_ANDROID_ABI +JNIEnv *SwiftFirebase_GetJavaEnvironment(void) +{ + return g_Env; +} + +FIREBASE_ANDROID_ABI +JavaVM *SwiftFirebase_GetJVM(void) +{ + return g_VM; +} diff --git a/Sources/FirebaseAndroid/log.h b/Sources/FirebaseAndroid/log.h new file mode 100644 index 0000000..dc68eb8 --- /dev/null +++ b/Sources/FirebaseAndroid/log.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + +#ifndef SwiftFirebase_FirebaseAndroidShim_logging_h +#define SwiftFirebase_FirebaseAndroidShim_logging_h + +#include + +#define FIREBASE_ANDROID_LOG(level, tag, ...) __android_log_print(level, tag, __VA_ARGS__) +#define FIREBASE_ANDROID_TAG "company.thebrowser.firebase" + +#define LOG_DEBUG(...) FIREBASE_ANDROID_LOG(ANDROID_LOG_DEBUG, FIREBASE_ANDROID_TAG, __VA_ARGS__) +#define LOG_VERBOSE(...) FIREBASE_ANDROID_LOG(ANDROID_LOG_VERBOSE, FIREBASE_ANDROID_TAG, __VA_ARGS__) +#define LOG_INFO(...) FIREBASE_ANDROID_LOG(ANDROID_LOG_INFO, FIREBASE_ANDROID_TAG, __VA_ARGS__) +#define LOG_WARN(...) FIREBASE_ANDROID_LOG(ANDROID_LOG_WARN, FIREBASE_ANDROID_TAG, __VA_ARGS__) +#define LOG_ERROR(...) FIREBASE_ANDROID_LOG(ANDROID_LOG_ERROR, FIREBASE_ANDROID_TAG, __VA_ARGS__) + +#endif