Closed djs-code closed 8 months ago
For additional context, the UIFocus family of APIs is related to the Full Keyboard Access accessibility setting on iPadOS.
Hi thanks for reporting this, from a cursory look I believe that the exception description may be misleading... We don't do anything with the UIFocus API nor do we implement _wantsPriorityOverFocusUpdates
. In fact I searched the entire project for the word "focus" case-insensitive and we don't even have that word in the code base. Also I don't actually see the MPAppDelegateProxy
class nor the MPSurrogateAppDelegate
class that it forwards to in the stack trace at all. In fact I don't see the mParticle framework in the trace at all, which is strange given the exception message.
I do see the following line in the stack trace just before the exception is triggered:
-[UIResponder(UIFocusAdditions) _shouldSkipKeyCommand:forMovement:]
This looks like it might be an internal Apple category as it says it's inside UIKitCore.
My best guess is this is an iOS 17 bug. Can you try a couple of things:
proxyAppDelegate
to false in MParticleOptions and see if it still triggers but this time with a different class name in the exception message?Otherwise, I'm not sure what we can do. We don't use the UIFocus API at all in any way that I can see, so there's nothing we can remove.
Hi @einsteinx2, thanks for the response. Indeed, I do not see any usage of the UIFocus APIs in the mParticle iOS SDK. From my investigation, I've concluded that this is happening because our App Delegate is a subclass of UIResponder
, whose respondsToSelector:
returns YES
for _wantsPriorityOverFocusUpdates
.
The selector resolution machinery here is certainly acting in a way I do not expect, but I suspect a possible workaround for this might be modifying [MPAppDelegateProxy respondsToSelector:]
as follows:
- (BOOL)respondsToSelector:(SEL)aSelector {
BOOL respondsToSelector = NO;
if (aSelector == originalAppDelegateSelector) {
respondsToSelector = YES;
} else if ([_originalAppDelegate respondsToSelector:aSelector] && !([[NSProcessInfo processInfo] operatingSystemVersion].majorVersion >= 17 && aSelector == NSSelectorFromString(@"_wantsPriorityOverFocusUpdates"))) {
respondsToSelector = YES;
} else if ([self.surrogateAppDelegate implementsSelector:aSelector]) {
respondsToSelector = YES;
}
return respondsToSelector;
}
@djs-code thanks for the quick follow up. I'm hesitant to add a workaround like this to the code, as this will likely be fixed by Apple shortly and having the App Delegate subclass UIResponder
is not a common pattern afaik, but the workaround will end up in the codebase forever.
Since we're already calling [_originalAppDelegate respondsToSelector:aSelector]
, would you be able to implement the !([[NSProcessInfo processInfo] operatingSystemVersion].majorVersion >= 17 && aSelector == NSSelectorFromString(@"_wantsPriorityOverFocusUpdates"))
check in your App delegate's own - (BOOL)respondsToSelector:(SEL)aSelector
method? If you return NO on that condition, we will then also return NO in the proxy, which should achieve the same result.
Since Apple seems to be indicating that _wantsPriorityOverFocusUpdates
is no longer supported (even though they seem to still be using it, which is probably the real bug here) I assume you don't actually need to handle those selectors anyway. Also if we added it to the proxy, it would also not be handled by your App Delegate since we are responding to respondsToSelector
for you, so if I'm understanding this correctly, putting it in your own app delegate should have the exact same result as modifying it in the SDK's proxy class.
Also that would be a great way to quickly confirm that it does fix the issue. If it does fix it, we can have some internal discussions about whether this belongs in the SDK or in customers' app code and in the meantime you can immediately release an app update with the fix.
Dear @einsteinx2 and mParticle Support team,
we are also experiencing the same issue / crashes on iOS as originally reported.
Our current SDK versions:
i also checked the source code for MPAppDelegateProxy.m class
I can see that original proposed solution is present now inside your mParticle SDK source code:
- (BOOL)respondsToSelector:(SEL)aSelector {
BOOL respondsToSelector = NO;
if (aSelector == originalAppDelegateSelector) {
respondsToSelector = YES;
} else if ([_originalAppDelegate respondsToSelector:aSelector]) {
respondsToSelector = YES;
} else if ([self.surrogateAppDelegate implementsSelector:aSelector]) {
respondsToSelector = YES;
}
return respondsToSelector;
}
however we still saw the crashes.
Do you think you can investigate it further?
Here is the crash details:
SoFiApplication.sendEvent(_:)
NSInternalInconsistencyException - Class MPAppDelegateProxy implements _wantsPriorityOverFocusUpdates, which is no longer supported.
Thanks again!
the workaround mentioned here isn't working, and this's still affecting many ipad users
@arolan This workaround suggested here is not already included in the MPAppDelegateProxy.m class. Compare the 2nd conditional statement in the code you provided and the suggested workaround bellow.
- (BOOL)respondsToSelector:(SEL)aSelector {
BOOL respondsToSelector = NO;
if (aSelector == originalAppDelegateSelector) {
respondsToSelector = YES;
} else if ([_originalAppDelegate respondsToSelector:aSelector] && !([[NSProcessInfo processInfo] operatingSystemVersion].majorVersion >= 17 && aSelector == NSSelectorFromString(@"_wantsPriorityOverFocusUpdates"))) {
respondsToSelector = YES;
} else if ([self.surrogateAppDelegate implementsSelector:aSelector]) {
respondsToSelector = YES;
}
return respondsToSelector;
}
@BrandonStalnaker also the suggested workaround, isn't working. [assuming that we can put this on your lib]
- (BOOL)respondsToSelector:(SEL)aSelector {
BOOL respondsToSelector = NO;
if (aSelector == originalAppDelegateSelector) {
respondsToSelector = YES;
} else if ([_originalAppDelegate respondsToSelector:aSelector] && !([[NSProcessInfo processInfo] operatingSystemVersion].majorVersion >= 17 && aSelector == NSSelectorFromString(@"_wantsPriorityOverFocusUpdates"))) {
respondsToSelector = YES;
} else if ([self.surrogateAppDelegate implementsSelector:aSelector]) {
respondsToSelector = YES;
}
return respondsToSelector;
}
We're seeing crashes on iPadOS 17 which seem to be related to the
UIFocus
family of APIs:Class MPAppDelegateProxy implements _wantsPriorityOverFocusUpdates, which is no longer supported.
Our
AppDelegate
implementation inherits fromUIResponder
, and a cursory look into MPAppDelegateProxy.m and MPSurrogateAppDelegate.h suggests we might be able to work around this by switching it toNSObject
. That said, I don't like the idea of cuttingAppDelegate
out of the responder chain in this day and age.