Skip to content

Commit 99bac53

Browse files
authored
Merge a56bd70 into 5d44914
2 parents 5d44914 + a56bd70 commit 99bac53

File tree

6 files changed

+374
-87
lines changed

6 files changed

+374
-87
lines changed

AGENTS.md

Lines changed: 66 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Introduction
22

3+
> **Note on Document Formatting:** This document (`Jules.md`) should be
4+
> maintained with lines word-wrapped to a maximum of 80 characters to ensure
5+
> readability across various editors and terminals.
6+
37
This document provides context and guidance for AI agents (like Jules) when
48
making changes to the Firebase C++ SDK repository. It covers essential
59
information about the repository's structure, setup, testing procedures, API
@@ -34,8 +38,8 @@ instructions for your specific platform.
3438
* **Android SDK & NDK**: Required for building Android libraries. `sdkmanager`
3539
can be used for installation. CMake for Android (version 3.10.2
3640
recommended) is also needed.
37-
* **(Windows Only) Strings**: From Microsoft Sysinternals, required for Android
38-
builds on Windows.
41+
* **(Windows Only) Strings**: From Microsoft Sysinternals, required for
42+
Android builds on Windows.
3943
* **Cocoapods**: Required for building iOS or tvOS libraries.
4044

4145
## Building the SDK
@@ -74,9 +78,10 @@ generated in each library's build directory (e.g.,
7478

7579
### Desktop Platform Setup Details
7680

77-
When setting up for desktop, if you are using an iOS `GoogleService-Info.plist`
78-
file, convert it to the required `google-services-desktop.json` using the
79-
script: `python generate_xml_from_google_services_json.py --plist -i GoogleService-Info.plist`
81+
When setting up for desktop, if you are using an iOS
82+
`GoogleService-Info.plist` file, convert it to the required
83+
`google-services-desktop.json` using the script:
84+
`python generate_xml_from_google_services_json.py --plist -i GoogleService-Info.plist`
8085
(run this from the script's directory, ensuring the plist file is accessible).
8186

8287
The desktop SDK searches for configuration files in the current working
@@ -175,8 +180,9 @@ Database).
175180
parameters if not relying on a `google-services.json` or
176181
`GoogleService-Info.plist` file.
177182
2. **Service Instances**: Once `firebase::App` is initialized, you generally
178-
obtain instances of specific Firebase services using a static `GetInstance()`
179-
method on the service's class, passing the `firebase::App` object.
183+
obtain instances of specific Firebase services using a static
184+
`GetInstance()` method on the service's class, passing the `firebase::App`
185+
object.
180186
* Examples for services like Auth, Database, Storage, Firestore:
181187
* `firebase::auth::Auth* auth = firebase::auth::Auth::GetAuth(app, &init_result);`
182188
* `firebase::database::Database* database = firebase::database::Database::GetInstance(app, &init_result);`
@@ -192,8 +198,8 @@ Database).
192198
called as global functions within the `firebase::analytics` namespace,
193199
rather than on an instance object obtained via `GetInstance()`.
194200
Refer to the specific product's header file for its exact
195-
initialization mechanism if it deviates from the common `GetInstance(app, ...)`
196-
pattern.
201+
initialization mechanism if it deviates from the common
202+
`GetInstance(app, ...)` pattern.
197203

198204
### Asynchronous Operations: `firebase::Future<T>`
199205

@@ -205,8 +211,8 @@ where `T` is the type of the expected result.
205211
`kFutureStatusInvalid`.
206212
* **Getting Results**: Once `future.status() == kFutureStatusComplete`:
207213
* Check for errors: `future.error()`. A value of `0` (e.g.,
208-
`firebase::auth::kAuthErrorNone`, `firebase::database::kErrorNone`)
209-
usually indicates success.
214+
`firebase::auth::kAuthErrorNone`,
215+
`firebase::database::kErrorNone`) usually indicates success.
210216
* Get the error message: `future.error_message()`.
211217
* Get the result: `future.result()`. This returns a pointer to the result
212218
object of type `T`. The result is only valid if `future.error()`
@@ -218,8 +224,8 @@ where `T` is the type of the expected result.
218224

219225
### Core Classes and Operations (Examples from Auth and Database)
220226

221-
While each Firebase product has its own specific classes, the following examples
222-
illustrate common API patterns:
227+
While each Firebase product has its own specific classes, the following
228+
examples illustrate common API patterns:
223229

224230
* **`firebase::auth::Auth`**: The main entry point for Firebase
225231
Authentication.
@@ -305,6 +311,12 @@ API documentation.
305311
as mentioned in `CONTRIBUTING.md`.
306312
* **Formatting**: Use `python3 scripts/format_code.py -git_diff -verbose` to
307313
format your code before committing.
314+
* **Naming Precision for Dynamic Systems**: Function names should precisely
315+
reflect their behavior, especially in systems with dynamic or asynchronous
316+
interactions. For example, a function that processes a list of items should
317+
be named differently from one that operates on a single, specific item
318+
captured asynchronously. Regularly re-evaluate function names as
319+
requirements evolve to maintain clarity.
308320

309321
## Comments
310322

@@ -328,8 +340,9 @@ API documentation.
328340
* **Check `Future` status and errors**: Always check `future.status()` and
329341
`future.error()` before attempting to use `future.result()`.
330342
* A common success code is `0` (e.g.,
331-
`firebase::auth::kAuthErrorNone`, `firebase::database::kErrorNone`).
332-
Other specific error codes are defined per module (e.g.,
343+
`firebase::auth::kAuthErrorNone`,
344+
`firebase::database::kErrorNone`). Other specific error codes are
345+
defined per module (e.g.,
333346
`firebase::auth::kAuthErrorUserNotFound`).
334347
* **Callback error parameters**: When using listeners or other callbacks,
335348
always check the provided error code and message before processing the
@@ -362,6 +375,13 @@ API documentation.
362375
otherwise ensuring the `Future` completes its course, particularly for
363376
operations with side effects or those that allocate significant backend
364377
resources.
378+
* **Lifecycle of Queued Callbacks/Blocks**: If blocks or callbacks are queued
379+
to be run upon an asynchronous event (e.g., an App Delegate class being set
380+
or a Future completing), clearly define and document their lifecycle.
381+
Determine if they are one-shot (cleared after first execution) or
382+
persistent (intended to run for multiple or future events). This impacts
383+
how associated data and the blocks themselves are stored and cleared,
384+
preventing memory leaks or unexpected multiple executions.
365385

366386
## Immutability
367387

@@ -397,6 +417,29 @@ API documentation.
397417
integration, it can occasionally be a factor to consider when debugging app
398418
delegate behavior or integrating with other libraries that also perform
399419
swizzling.
420+
When implementing or interacting with swizzling, especially for App Delegate
421+
methods like `[UIApplication setDelegate:]`:
422+
* Be highly aware that `setDelegate:` can be called multiple times
423+
with different delegate class instances, including proxy classes
424+
from other libraries (e.g., GUL - Google Utilities). Swizzling
425+
logic must be robust against being invoked multiple times for the
426+
same effective method on the same class or on classes in a
427+
hierarchy. An idempotency check (i.e., if the method's current IMP
428+
is already the target swizzled IMP, do nothing more for that
429+
specific swizzle attempt) in any swizzling utility can prevent
430+
issues like recursion.
431+
* When tracking unique App Delegate classes (e.g., for applying hooks
432+
or callbacks via swizzling), consider the class hierarchy. If a
433+
superclass has already been processed, processing a subclass for
434+
the same inherited methods might be redundant or problematic. A
435+
strategy to check if a newly set delegate is a subclass of an
436+
already processed delegate can prevent such issues.
437+
* For code that runs very early in the application lifecycle on
438+
iOS/macOS (e.g., `+load` methods, static initializers involved in
439+
swizzling), prefer using `NSLog` directly over custom logging
440+
frameworks if there's any uncertainty about whether the custom
441+
framework is fully initialized, to avoid crashes during logging
442+
itself.
400443

401444
## Class and File Structure
402445

@@ -462,9 +505,9 @@ management:
462505
module, but the fundamental responsibility for creation and deletion in
463506
typical scenarios lies with the Pimpl class itself.
464507

465-
It's crucial to correctly implement all these aspects (constructors, destructor,
466-
copy/move operators) when dealing with raw pointer Pimpls to prevent memory
467-
leaks, dangling pointers, or double deletions.
508+
It's crucial to correctly implement all these aspects (constructors,
509+
destructor, copy/move operators) when dealing with raw pointer Pimpls to
510+
prevent memory leaks, dangling pointers, or double deletions.
468511

469512
## Namespace Usage
470513

@@ -576,3 +619,8 @@ practices detailed in `Jules.md`.
576619
tests as described in the 'Testing' section of `Jules.md`.
577620
* **Commit Messages**: Follow standard commit message guidelines. A brief
578621
summary line, followed by a more detailed explanation if necessary.
622+
* **Tool Limitations & Path Specificity**: If codebase search tools (like
623+
`grep` or recursive `ls`) are limited or unavailable, and initial attempts
624+
to locate files/modules based on common directory structures are
625+
unsuccessful, explicitly ask for more specific paths rather than assuming a
626+
module doesn't exist or contains no relevant code.

app/src/invites/ios/invites_ios_startup.mm

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,7 @@ @implementation UIApplication (FIRFBI)
286286
+ (void)load {
287287
// C++ constructors may not be called yet so call NSLog rather than LogDebug.
288288
NSLog(@"Loading UIApplication category for Firebase App");
289-
::firebase::util::ForEachAppDelegateClass(^(Class clazz) {
289+
::firebase::util::RunOnAppDelegateClasses(^(Class clazz) {
290290
::firebase::invites::HookAppDelegateMethods(clazz);
291291
});
292292
}

app/src/util_ios.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -185,10 +185,12 @@ typedef BOOL (
185185
id self, SEL selector_value, UIApplication *application,
186186
NSUserActivity *user_activity, void (^restoration_handler)(NSArray *));
187187

188-
// Call the given block once for every Objective-C class that exists that
189-
// implements the UIApplicationDelegate protocol (except for those in a
190-
// blacklist we keep).
191-
void ForEachAppDelegateClass(void (^block)(Class));
188+
// Calls the given block for each unique Objective-C class that has been
189+
// previously passed to [UIApplication setDelegate:]. The block is executed
190+
// immediately for all currently known unique delegate classes.
191+
// Additionally, the block is queued to be executed if any new, unique
192+
// Objective-C class is passed to [UIApplication setDelegate:] in the future.
193+
void RunOnAppDelegateClasses(void (^block)(Class));
192194

193195
// Convert a string array into an NSMutableArray.
194196
NSMutableArray *StringVectorToNSMutableArray(

0 commit comments

Comments
 (0)