Skip to content

Commit cb0f182

Browse files
committed
FirebaseAndroid: introduce the new JNI module for Android support
In order to interact with the C++ Firebase SDK, we need to have access to the JVM and the JavaEnvironment. Introduce a JNI layer which allows us to capture this information when loaded. Additionally, register a `company.thebrowser.Native.RegisterActivity` method to allow us access to the `Activity`. This is required to be called before the Firebase layer is accessed by the application.
1 parent f2a9ca8 commit cb0f182

File tree

7 files changed

+156
-0
lines changed

7 files changed

+156
-0
lines changed

CMakeLists.txt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@
33
cmake_minimum_required(VERSION 3.25)
44
project(swift-firebase
55
LANGUAGES Swift)
6+
if(ANDROID)
7+
enable_language(C)
8+
include(FindJava)
9+
include(UseJava)
10+
endif()
611

712
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
813
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
@@ -39,6 +44,10 @@ else()
3944
message(FATAL_ERROR "unsupported firebase-cpp-sdk platform")
4045
endif()
4146

47+
if(ANDROID)
48+
add_subdirectory(Sources/FirebaseAndroid)
49+
endif()
50+
4251
add_library(FirebaseCore SHARED
4352
Sources/FirebaseCore/FirebaseApp+Swift.swift
4453
Sources/FirebaseCore/FirebaseConfiguration.swift
@@ -55,6 +64,10 @@ target_link_libraries(FirebaseCore PRIVATE
5564
firebase_app
5665
flatbuffers
5766
zlibstatic)
67+
if(ANDROID)
68+
target_link_libraries(FirebaseCore PRIVATE
69+
FirebaseAndroidJNI)
70+
endif()
5871

5972
add_library(FirebaseAuth SHARED
6073
Sources/FirebaseAuth/AuthStateDidChangeListenerHandle.swift
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# SPDX-License-Identifier: BSD-3-Clause
2+
3+
add_library(FirebaseAndroidJNI SHARED
4+
jni.c)
5+
target_include_directories(FirebaseAndroidJNI PUBLIC
6+
include)
7+
target_link_libraries(FirebaseAndroidJNI PRIVATE
8+
log)
9+

Sources/FirebaseAndroid/abi.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/* SPDX-License-Identifier: BSD-3-Clause */
2+
3+
#ifndef SwiftFirebase_FirebaseAndroidShim_abi_h
4+
#define SwiftFirebase_FirebaseAndroidShim_abi_h
5+
6+
#if defined(FirebaseAndroidJNI_EXPORTS)
7+
#define FIREBASE_ANDROID_ABI __attribute__((__visibility__("default")))
8+
#else
9+
#define FIREBASE_ANDROID_ABI __attribute__((__visibility__("default")))
10+
#endif
11+
12+
#endif
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/* SPDX-License-Identifier: BSD-3-Clause */
2+
3+
#ifndef SwiftFirebase_FirebaseAndroidShim_FirebaseAndroid_h
4+
#define SwiftFirebase_FirebaseAndroidShim_FirebaseAndroid_h
5+
6+
#include <jni.h>
7+
8+
#if defined(__cplusplus)
9+
extern "C" {
10+
#endif
11+
12+
jobject _Nullable SwiftFirebase_GetActivity(void);
13+
JNIEnv * _Nullable SwiftFirebase_GetJavaEnvironment(void);
14+
JavaVM * _Nullable SwiftFirebase_GetJVM(void);
15+
16+
#if defined(__cplusplus)
17+
}
18+
#endif
19+
20+
#endif
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
/* SPDX-License-Identifier: BSD-3-Clause */
2+
3+
module FirebaseAndroid {
4+
header "FirebaseAndroid.h"
5+
export *
6+
}

Sources/FirebaseAndroid/jni.c

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/* SPDX-License-Identifier: BSD-3-Clause */
2+
3+
#include "FirebaseAndroid.h"
4+
#include "abi.h"
5+
#include "log.h"
6+
7+
#include <assert.h>
8+
9+
static JavaVM *g_VM;
10+
static JNIEnv *g_Env;
11+
static jobject *g_Activity;
12+
13+
#define N_ELEMENTS(array) (sizeof((array)) / sizeof(*(array)))
14+
15+
static const char kClassPath[] = "company/thebrowser/Native";
16+
17+
static jboolean
18+
SwiftFirebase_RegisterActivity(JNIEnv *env, jobject *this, jobject *activity)
19+
{
20+
assert(g_Activity == NULL && "re-registeration of activity");
21+
if (g_Activity) return JNI_FALSE;
22+
23+
g_Activity = activity;
24+
return JNI_TRUE;
25+
}
26+
27+
static JNINativeMethod kMethods[] = {
28+
{ "RegisterActivity", "()Z", SwiftFirebase_RegisterActivity },
29+
};
30+
31+
static void
32+
RegisterNativeMethods(JNIEnv *env)
33+
{
34+
jclass class;
35+
jint result;
36+
37+
class = (*env)->FindClass(env, kClassPath);
38+
if (class == NULL) {
39+
LOG_ERROR("unable to find class '%s'", kClassPath);
40+
return;
41+
}
42+
LOG_DEBUG("located class path '%s': %p", kClassPath, class);
43+
44+
result = (*env)->RegisterNatives(env, class, kMethods, N_ELEMENTS(kMethods));
45+
if (result < 0) {
46+
LOG_ERROR("JVM.RegisterNatives(%s): %u", kClassPath, result);
47+
return;
48+
}
49+
LOG_DEBUG("registered %u methods", N_ELEMENTS(kMethods));
50+
}
51+
52+
FIREBASE_ANDROID_ABI
53+
jint JNI_OnLoad(JavaVM *vm, void *reserved)
54+
{
55+
g_VM = vm;
56+
if ((*g_VM)->GetEnv(g_VM, (void **)&g_Env, JNI_VERSION_1_6) == JNI_OK)
57+
return JNI_VERSION_1_6;
58+
RegisterNativeMethods(g_Env);
59+
return -1;
60+
}
61+
62+
FIREBASE_ANDROID_ABI
63+
jobject SwiftFirebase_GetActivity(void)
64+
{
65+
assert(g_Activity && "`GetActivity` invoked before `RegisterActivity`");
66+
return *g_Activity;
67+
}
68+
69+
FIREBASE_ANDROID_ABI
70+
JNIEnv *SwiftFirebase_GetJavaEnvironment(void)
71+
{
72+
return g_Env;
73+
}
74+
75+
FIREBASE_ANDROID_ABI
76+
JavaVM *SwiftFirebase_GetJVM(void)
77+
{
78+
return g_VM;
79+
}

Sources/FirebaseAndroid/log.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/* SPDX-License-Identifier: BSD-3-Clause */
2+
3+
#ifndef SwiftFirebase_FirebaseAndroidShim_logging_h
4+
#define SwiftFirebase_FirebaseAndroidShim_logging_h
5+
6+
#include <android/log.h>
7+
8+
#define FIREBASE_ANDROID_LOG(level, tag, ...) __android_log_print(level, tag, __VA_ARGS__)
9+
#define FIREBASE_ANDROID_TAG "company.thebrowser.firebase"
10+
11+
#define LOG_DEBUG(...) FIREBASE_ANDROID_LOG(ANDROID_LOG_DEBUG, FIREBASE_ANDROID_TAG, __VA_ARGS__)
12+
#define LOG_VERBOSE(...) FIREBASE_ANDROID_LOG(ANDROID_LOG_VERBOSE, FIREBASE_ANDROID_TAG, __VA_ARGS__)
13+
#define LOG_INFO(...) FIREBASE_ANDROID_LOG(ANDROID_LOG_INFO, FIREBASE_ANDROID_TAG, __VA_ARGS__)
14+
#define LOG_WARN(...) FIREBASE_ANDROID_LOG(ANDROID_LOG_WARN, FIREBASE_ANDROID_TAG, __VA_ARGS__)
15+
#define LOG_ERROR(...) FIREBASE_ANDROID_LOG(ANDROID_LOG_ERROR, FIREBASE_ANDROID_TAG, __VA_ARGS__)
16+
17+
#endif

0 commit comments

Comments
 (0)