Skip to content

Commit 214489d

Browse files
Refactor ForEachAppDelegateClass to use standard iOS/tvOS techniques
Instead of enumerating all classes, this change modifies ForEachAppDelegateClass to use `[UIApplication sharedApplication].delegate.class` to get the single app delegate class in use. This approach is compatible with iOS 15 and later.
1 parent 5ea2a16 commit 214489d

File tree

1 file changed

+38
-27
lines changed

1 file changed

+38
-27
lines changed

app/src/util_ios.mm

Lines changed: 38 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -80,37 +80,48 @@ - (BOOL)application:(UIApplication *)application
8080
namespace util {
8181

8282
void ForEachAppDelegateClass(void (^block)(Class)) {
83-
unsigned int number_of_classes;
84-
Class *classes = objc_copyClassList(&number_of_classes);
85-
for (unsigned int i = 0; i < number_of_classes; i++) {
86-
Class clazz = classes[i];
87-
if (class_conformsToProtocol(clazz, @protocol(UIApplicationDelegate))) {
88-
const char *class_name = class_getName(clazz);
89-
bool blacklisted = false;
90-
static const char *kClassNameBlacklist[] = {
91-
// Declared in Firebase Analytics:
92-
// //googlemac/iPhone/Firebase/Analytics/Sources/ApplicationDelegate/
93-
// FIRAAppDelegateProxy.m
94-
"FIRAAppDelegate",
95-
// Declared here.
96-
"FIRSAMAppDelegate"};
97-
for (size_t i = 0; i < FIREBASE_ARRAYSIZE(kClassNameBlacklist); ++i) {
98-
if (strcmp(class_name, kClassNameBlacklist[i]) == 0) {
99-
blacklisted = true;
100-
break;
101-
}
83+
// Get the application delegate class directly.
84+
// This assumes that the application has a single app delegate, which is the
85+
// standard practice for iOS/tvOS apps.
86+
// This needs to be called at or after +load time, when the application delegate is set.
87+
Class appDelegateClass = nil;
88+
UIApplication *sharedApplication = [UIApplication sharedApplication];
89+
if (sharedApplication) {
90+
id<UIApplicationDelegate> appDelegate = sharedApplication.delegate;
91+
if (appDelegate) {
92+
appDelegateClass = [appDelegate class];
93+
}
94+
}
95+
96+
if (appDelegateClass && class_conformsToProtocol(appDelegateClass, @protocol(UIApplicationDelegate))) {
97+
const char *class_name = class_getName(appDelegateClass);
98+
bool blacklisted = false;
99+
static const char *kClassNameBlacklist[] = {
100+
// Declared in Firebase Analytics:
101+
// //googlemac/iPhone/Firebase/Analytics/Sources/ApplicationDelegate/
102+
// FIRAAppDelegateProxy.m
103+
"FIRAAppDelegate",
104+
// Declared here.
105+
"FIRSAMAppDelegate"};
106+
for (size_t i = 0; i < FIREBASE_ARRAYSIZE(kClassNameBlacklist); ++i) {
107+
if (strcmp(class_name, kClassNameBlacklist[i]) == 0) {
108+
blacklisted = true;
109+
break;
102110
}
103-
if (!blacklisted) {
104-
if (GetLogLevel() <= kLogLevelDebug) {
105-
// Call NSLog directly because we may be in a +load method,
106-
// and C++ classes may not be constructed yet.
107-
NSLog(@"Firebase: Found UIApplicationDelegate class %s", class_name);
108-
}
109-
block(clazz);
111+
}
112+
if (!blacklisted) {
113+
if (GetLogLevel() <= kLogLevelDebug) {
114+
// Call NSLog directly because we may be in a +load method,
115+
// and C++ classes may not be constructed yet.
116+
NSLog(@"Firebase: Using UIApplicationDelegate class %s", class_name);
110117
}
118+
block(appDelegateClass);
119+
}
120+
} else {
121+
if (GetLogLevel() <= kLogLevelWarning) {
122+
NSLog(@"Firebase: Could not find a valid UIApplicationDelegate class.");
111123
}
112124
}
113-
free(classes);
114125
}
115126

116127
NSDictionary *StringMapToNSDictionary(const std::map<std::string, std::string> &string_map) {

0 commit comments

Comments
 (0)