Skip to content

Commit c96a8c4

Browse files
smilesa-maurice
authored andcommitted
Added ability to create a firebase::App for existing FIRApp/FirebaseApp.
iOS FIRApp and Android FirebaseApp objects are serialized and are therefore restored when the application restarts. A firebase::App could only be created if a FIRApp/FirebaseApp was not already present unless the FirebaseApp was a default instance. This prevented developers from creating named firebase::App instances since upon application restart it would not be possible to create a firebase::App as a FirebaseApp would already exist with the same name. Furthermore, once a named firebase::App object was destroyed it wasn't possible to recreate the same object in the same session as a FIRApp/FirebaseApp with the same name would be present. This changes the behavior of firebase::App on iOS and Android to allow connection with an existing FIRApp/FirebaseApp object. If the FIRApp/FirebaseApp has different options than those requested by the caller of firebase::App::Create(), the existing FIRApp/FirebaseApp object is destroyed and recreated with the requested options. PiperOrigin-RevId: 261147650
1 parent 52cfe5b commit c96a8c4

File tree

8 files changed

+569
-344
lines changed

8 files changed

+569
-344
lines changed

app/src/app_android.cc

Lines changed: 174 additions & 120 deletions
Large diffs are not rendered by default.

app/src/app_common.cc

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@
4747
#endif
4848

4949
namespace FIREBASE_NAMESPACE {
50+
51+
// Default app name.
52+
const char* const kDefaultAppName = "__FIRAPP_DEFAULT";
53+
5054
namespace app_common {
5155

5256
// clang-format=off
@@ -232,14 +236,13 @@ static std::map<std::string, UniquePtr<AppData>>* g_apps;
232236
static App* g_default_app = nullptr;
233237
LibraryRegistry* LibraryRegistry::library_registry_ = nullptr;
234238

235-
App* AddApp(App* app, bool is_default,
236-
std::map<std::string, InitResult>* results) {
239+
App* AddApp(App* app, std::map<std::string, InitResult>* results) {
237240
bool created_first_app = false;
238241
assert(app);
239242
App* existing_app = FindAppByName(app->name());
240243
FIREBASE_ASSERT_RETURN(nullptr, !existing_app);
241244
MutexLock lock(g_app_mutex);
242-
if (is_default) {
245+
if (IsDefaultAppName(app->name())) {
243246
assert(!g_default_app);
244247
g_default_app = app;
245248
created_first_app = true;
@@ -352,6 +355,11 @@ void DestroyAllApps() {
352355
}
353356
}
354357

358+
// Determine whether the specified app name refers to the default app.
359+
bool IsDefaultAppName(const char* name) {
360+
return strcmp(kDefaultAppName, name) == 0;
361+
}
362+
355363
void RegisterLibrary(const char* library, const char* version) {
356364
MutexLock lock(g_app_mutex);
357365
LibraryRegistry* registry = LibraryRegistry::Initialize();

app/src/app_common.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@
2929
#endif
3030

3131
namespace FIREBASE_NAMESPACE {
32+
33+
// Default app name.
34+
extern const char* const kDefaultAppName;
35+
3236
namespace app_common {
3337

3438
// Prefix applied to components of Firebase user agent strings.
@@ -45,8 +49,7 @@ extern const char* kCpuArchitecture;
4549
extern const char* kApiClientHeader;
4650

4751
// Add an app to the set of apps.
48-
App* AddApp(App* app, bool is_default,
49-
std::map<std::string, InitResult>* results);
52+
App* AddApp(App* app, std::map<std::string, InitResult>* results);
5053

5154
// Find an app in the set of apps.
5255
App* FindAppByName(const char* name);
@@ -65,6 +68,9 @@ void RemoveApp(App* app);
6568
// Destroy all apps.
6669
void DestroyAllApps();
6770

71+
// Determine whether the specified app name refers to the default app.
72+
bool IsDefaultAppName(const char* name);
73+
6874
// Register a library which uses this SDK.
6975
// Library registrations are not thread safe as we build the user agent string
7076
// once and return it from the UserAgent() method.

app/src/app_desktop.cc

Lines changed: 60 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -44,27 +44,15 @@ static std::string g_default_config_path; // NOLINT
4444

4545
} // namespace internal
4646

47-
// The default App name, the same string as what are used for Android and iOS.
48-
const char* const kDefaultAppName = "__FIRAPP_DEFAULT";
49-
50-
App::App() {
51-
LogDebug("Creating firebase::App for %s", kFirebaseVersionString);
52-
data_ = new internal::PrivateAppData();
53-
}
54-
55-
App::~App() {
56-
app_common::RemoveApp(this);
57-
// Once we use data_, we should delete it here.
58-
delete static_cast<internal::PrivateAppData*>(data_);
59-
data_ = nullptr;
60-
}
47+
namespace {
6148

6249
// Size is arbitrary, just making sure that there is a sane limit.
63-
const int kMaxBuffersize = 1024 * 500;
50+
static const int kMaxBuffersize = 1024 * 500;
6451

6552
// Attempts to load a config file from the path specified, and use it to
6653
// populate the AppOptions pointer. Returns true on success, false otherwise.
67-
bool LoadFromJsonConfigFile(const char* path, AppOptions* options) {
54+
static bool LoadAppOptionsFromJsonConfigFile(const char* path,
55+
AppOptions* options) {
6856
bool loaded_options = false;
6957
std::ifstream infile(path, std::ifstream::binary);
7058
if (infile) {
@@ -91,54 +79,79 @@ bool LoadFromJsonConfigFile(const char* path, AppOptions* options) {
9179
return loaded_options;
9280
}
9381

94-
const char* kDefaultGoogleServicesNames[] = {"google-services-desktop.json",
95-
"google-services.json"};
96-
97-
// On desktop, if you create an app with no arguments, it will try to
98-
// load any data it can find from the google-services-desktop.json
99-
// file, or the google-services.json file, in that order.
100-
App* App::Create() {
82+
} // namespace
83+
84+
// Searches internal::g_default_config_path for filenames matching
85+
// kDefaultGoogleServicesNames attempting to load the app options from each
86+
// config file in turn.
87+
AppOptions* AppOptions::LoadDefault(AppOptions* options) {
88+
static const char* kDefaultGoogleServicesNames[] = {
89+
"google-services-desktop.json",
90+
"google-services.json"
91+
};
92+
bool allocated_options;
93+
if (options) {
94+
allocated_options = false;
95+
} else {
96+
options = new AppOptions();
97+
allocated_options = true;
98+
}
10199
std::string config_files;
102100
size_t number_of_config_filenames = sizeof(kDefaultGoogleServicesNames) /
103101
sizeof(kDefaultGoogleServicesNames[0]);
104102
for (size_t i = 0; i < number_of_config_filenames; i++) {
105-
AppOptions options;
106-
std::string full_path =
107-
internal::g_default_config_path + kDefaultGoogleServicesNames[i];
108-
109-
if (LoadFromJsonConfigFile(full_path.c_str(), &options)) {
110-
return Create(options);
103+
std::string full_path = internal::g_default_config_path +
104+
kDefaultGoogleServicesNames[i];
105+
if (LoadAppOptionsFromJsonConfigFile(full_path.c_str(), options)) {
106+
return options;
111107
}
112108
config_files += full_path;
113109
if (i < number_of_config_filenames - 1) config_files += ", ";
114110
}
115-
LogError(
116-
"Unable to load options for default app ([%s] are missing or "
117-
"malformed)",
118-
config_files.c_str());
111+
if (allocated_options) delete options;
112+
LogError("Unable to load Firebase app options ([%s] are missing or "
113+
"malformed)", config_files.c_str());
119114
return nullptr;
120115
}
121116

117+
App::App() {
118+
data_ = new internal::PrivateAppData();
119+
}
120+
121+
App::~App() {
122+
app_common::RemoveApp(this);
123+
// Once we use data_, we should delete it here.
124+
delete static_cast<internal::PrivateAppData*>(data_);
125+
data_ = nullptr;
126+
}
127+
128+
// On desktop, if you create an app with no arguments, it will try to
129+
// load any data it can find from the google-services-desktop.json
130+
// file, or the google-services.json file, in that order.
131+
App* App::Create() {
132+
AppOptions options;
133+
return AppOptions::LoadDefault(&options) ? Create(options) : nullptr;
134+
}
135+
122136
App* App::Create(const AppOptions& options) { // NOLINT
123137
return Create(options, kDefaultAppName);
124138
}
125139

126140
App* App::Create(const AppOptions& options, const char* name) { // NOLINT
127-
App* existing_app = GetInstance(name);
128-
if (existing_app) {
129-
LogError("firebase::App %s already created, options will not be applied.",
130-
name);
131-
return existing_app;
141+
App* app = GetInstance(name);
142+
if (app) {
143+
LogError("App %s already created, options will not be applied.", name);
144+
return app;
132145
}
133-
bool is_default_app = strcmp(kDefaultAppName, name) == 0;
134-
LogInfo("Firebase App initializing app %s (default %d).", name,
135-
is_default_app ? 1 : 0);
136-
137-
App* new_app = new App();
138-
new_app->name_ = name;
139-
new_app->options_ = options;
140-
141-
return app_common::AddApp(new_app, is_default_app, &new_app->init_results_);
146+
LogDebug("Creating Firebase App %s for %s", name, kFirebaseVersionString);
147+
AppOptions options_with_defaults = options;
148+
if (options_with_defaults.PopulateRequiredWithDefaults()) {
149+
app = new App();
150+
app->name_ = name;
151+
app->options_ = options_with_defaults;
152+
app = app_common::AddApp(app, &app->init_results_);
153+
}
154+
return app;
142155
}
143156

144157
App* App::GetInstance() { // NOLINT

0 commit comments

Comments
 (0)