Bug 52660 - iOS library that uses swizzling crashes on simulator due to no matching selector
Summary: iOS library that uses swizzling crashes on simulator due to no matching selector
Status: RESOLVED ANSWERED
Alias: None
Product: iOS
Classification: Xamarin
Component: Xamarin.iOS.dll ()
Version: XI 10.3 (iOS 10.2)
Hardware: Macintosh Mac OS
: --- normal
Target Milestone: Untriaged
Assignee: Bugzilla
URL:
Depends on:
Blocks:
 
Reported: 2017-02-22 03:03 UTC by jkasten
Modified: 2017-02-22 20:44 UTC (History)
3 users (show)

Tags:
Is this bug a regression?: No
Last known good build:

Notice (2018-05-24): bugzilla.xamarin.com is now in read-only mode.

Please join us on Visual Studio Developer Community and in the Xamarin and Mono organizations on GitHub to continue tracking issues. Bugzilla will remain available for reference in read-only mode. We will continue to work on open Bugzilla bugs, copy them to the new locations as needed for follow-up, and add the new items under Related Links.

Our sincere thanks to everyone who has contributed on this bug tracker over the years. Thanks also for your understanding as we make these adjustments and improvements for the future.


Please create a new report on Developer Community or GitHub with your current version information, steps to reproduce, and relevant error messages or log files if you are hitting an issue that looks similar to this resolved bug and you do not yet see a matching new report.

Related Links:
Status:
RESOLVED ANSWERED

Description jkasten 2017-02-22 03:03:40 UTC
The following crash only happens on the iOS simulator.

```
ObjCRuntime.RuntimeException: Cannot get the method descriptor for the selector 'oneSignalApplicationDidBecomeActive:' on the type 'Com.OneSignal.Sample.iOS.AppDelegate', because the selector does not correspond to a method
  at at (wrapper managed-to-native) UIKit.UIApplication:UIApplicationMain (int,string[],intptr,intptr)
  at UIKit.UIApplication.Main (System.String[] args, System.IntPtr principal, System.IntPtr delegate) [0x00005] in /Users/builder/data/lanes/3969/7beaef43/source/xamarin-macios/src/UIKit/UIApplication.cs:79
  at UIKit.UIApplication.Main (System.String[] args, System.String principalClassName, System.String delegateClassName) [0x00038] in /Users/builder/data/lanes/3969/7beaef43/source/xamarin-macios/src/UIKit/UIApplication.cs:63
  at Com.OneSignal.Sample.iOS.Application.Main (System.String[] args) [0x00008] in /Users/Kasten/Documents/OneSignal/OneSignal-Xamarin-SDK/Samples/Com.OneSignal.Sample.iOS/Main.cs:12
```

The crash can be reproduced by running the Com.OneSignal.Sample.iOS project in the OneSignal.sln below.
https://github.com/OneSignal/OneSignal-Xamarin-SDK/tree/3.0.0

This does not crash on real iOS devices, only an issue with the simulator.


If the following lines are added to the AppDelegate.cs in the project the issue no longer happens.
```
      [Export("oneSignalApplicationDidBecomeActive:")]
      public void OneSignalApplicationDidBecomeActive(UIApplication application)
      {
         OnActivated(application);
      }

      [Export("oneSignalApplicationWillResignActive:")]
      public void OneSignalApplicationWillResignActive(UIApplication application)
      {
         OnResignActivation(application);
      }

      [Export("oneSignalApplicationDidEnterBackground:")]
      public void OneSignalApplicationDidEnterBackground(UIApplication application)
      {
         DidEnterBackground(application);
      }

      [Export("oneSignalApplicationWillTerminate:")]
      public void OneSignalApplicationWillTerminate(UIApplication application)
      {
         WillTerminate(application);
      }
```

https://github.com/OneSignal/OneSignal-Xamarin-SDK/blob/3.0.0/Samples/Com.OneSignal.Sample.iOS/AppDelegate.cs


The sizzling is done in our native OneSignal iOS library noted in the links below.
https://github.com/OneSignal/OneSignal-iOS-SDK/blob/2.3.5/iOS_SDK/OneSignal/OneSignal.m#L1261
https://github.com/OneSignal/OneSignal-iOS-SDK/blob/2.3.5/iOS_SDK/OneSignal/UIApplicationDelegate%2BOneSignal.m#L128-L129
https://github.com/OneSignal/OneSignal-iOS-SDK/blob/2.3.5/iOS_SDK/OneSignal/UIApplicationDelegate%2BOneSignal.m#L258-L268

Please fix this simulator issue in a future Xamarin release and / or provide a work around that works at the plugin level rather than the app project level as I have listed above if possible.
Comment 1 Rolf Bjarne Kvinge [MSFT] 2017-02-22 10:05:37 UTC
The OneSignal library does not do method swizzling correctly.

In particular the _cmd argument is not correct when the library call the original implementation (for the exception you mention the _cmd argument is 'oneSignalApplicationDidBecomeActive:', when it should be 'applicationDidBecomeActive:'), which Xamarin.iOS requires to look up the correct managed method to call.

More information is available here: https://blog.newrelic.com/2014/04/16/right-way-to-swizzle/

It might be possible to add "--registrar:static" to the additional mtouch arguments in the project's iOS build to work around this problem.
Comment 2 jkasten 2017-02-22 20:44:10 UTC
Thanks for the work around flag. This is definitely better than having to include an export for each method just for iOS Simulator compatibility.

I went back and forth on with implementation of swizzling to use in our SDK between C functions and Objective-C selectors as the link you sent noted. I was able to get everything working the Object-C way and even works to call the original (by calling the renamed selector). Even though the article considers this "the wrong way". It has been battle tested in a large number of apps working this way without interfering with developer's AppDelegate selectors in native apps as well as other SDKs like Unity and Cordova. I also feel the Object-C implementation is easier to read.

However it does sound like the Objective-C way could change how the original selector sees itself as selector name. Will need to test this to see if our implementation has the same issue.

Anyway I think we will just tell our developers to use "--registrar:static" for now. Changing all our swizzling to use C functions is going to be an under taking in handling and testing all edge cases we have already solved and tested over the years.

You can mark this tick as resolved on your end.

Thanks.