Bug 46194 - UIApplicationLaunchOptionsUserActivityKey constant missing
Summary: UIApplicationLaunchOptionsUserActivityKey constant missing
Alias: None
Product: iOS
Classification: Xamarin
Component: Xamarin.iOS.dll ()
Version: XI 10.2 (iOS 10.1)
Hardware: Macintosh Mac OS
: Normal normal
Target Milestone: Future Cycle (TBD)
Assignee: Sebastien Pouliot
Depends on:
Reported: 2016-10-31 17:43 UTC by kkurz
Modified: 2016-11-11 16:08 UTC (History)
3 users (show)

Is this bug a regression?: ---
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:

Description kkurz 2016-10-31 17:43:32 UTC
CallKit calls public override bool FinishedLaunching(UIApplication application, NSDictionary launchOptions) with a launchOptions dictionary that looks like this:

  UIApplicationLaunchOptionsSourceApplicationKey = "com.apple.mobilephone";
  UIApplicationLaunchOptionsUserActivityDictionaryKey =     {
    UIApplicationLaunchOptionsUserActivityIdentifierKey = "525BBBAE-3972-4545-9181-42F5FDA131E4";
    UIApplicationLaunchOptionsUserActivityKey = "<NSUserActivity: 0x174238940>";
    UIApplicationLaunchOptionsUserActivityTypeKey = INStartAudioCallIntent;

I can pull the NSUserActivity dictionary out of launchOptions with:

var dict = launchOptions.ValueForKey(UIApplication.LaunchOptionsUserActivityDictionaryKey) as NSDictionary;

but I cannot get the NSUserActivity out of that dictionary because the constant UIApplicationLaunchOptionsUserActivityKey is not defined. I also don't think UIApplicationLaunchOptionsUserActivityIdentifierKey is defined and INStartAudioCallIntent is not defined as a valid UIApplicationLaunchOptionsUserActivityTypeKey value. This makes it hard to test the launchOptions and perform the appropriate actions.

I'm trying to do:

var dict = launchOptions.ValueForKey(UIApplication.LaunchOptionsUserActivityDictionaryKey) as NSDictionary;
NSUserActivity activity;
if (dict.TryGetValue(UIApplication.LaunchOptionsUserActivityKey, out activity))
  //some code to handle the activity...
Comment 1 kkurz 2016-10-31 17:44:42 UTC
EDIT: FinishedLaunching is called with that dictionary when a user taps a call log from the native Phone app to call back in a CallKit app.
Comment 2 kkurz 2016-11-01 17:33:38 UTC
FYI, you have this marked as "normal" and "future" cycle. It's currently holding up my CallKit release, as I'm failing test cases without the code that relies on these keys. Any way to bump the priority on this one?
Comment 3 Sebastien Pouliot 2016-11-01 18:28:59 UTC
You can load the constant by doing:

> var constant = Dlfcn.GetStringConstant (Libraries.UIKit.Handle, "UIApplicationLaunchOptionsUserActivityKey");

until a released version of XI has it included.
Comment 4 kkurz 2016-11-01 18:41:59 UTC
Thanks, now I'm getting errors about Libraries' protection level? Is there something else I need to do to be able to pass that IntPtr correctly?
Comment 5 Sebastien Pouliot 2016-11-01 18:47:42 UTC
Sorry, the handle I mentioned is not public, however you can get your own:

> var handle = Dlfcn.dlopen (Constants.UIKitLibrary, 0);
> var constant = Dlfcn.GetStringConstant (handle, "UIApplicationLaunchOptionsUserActivityKey");
Comment 6 kkurz 2016-11-01 20:56:02 UTC
So that compiles and runs, but seems to come back with an empty string for the constant...
Comment 7 Sebastien Pouliot 2016-11-01 21:29:35 UTC
An empty string or a null one ? In either case that's generally means it's (a) not a constant or (b) a typo.

Now a quick googl'ing makes it looks like it might not be a *constant* (a) but just a key named like one, e.g.

> id activity = [[options objectForKey:UIApplicationLaunchOptionsUserActivityDictionaryKey] objectForKey:@"UIApplicationLaunchOptionsUserActivityKey"];

^ note the difference in the usage.

In such case the key might not be in the headers (I'll double check) and won't be part of the bindings.

Have you tried using UIApplicationLaunchOptionsUserActivityKey as a NSString value ? something like:

> using (var key = new NSString ("UIApplicationLaunchOptionsUserActivityKey")) {
>    if (dict.TryGetValue (key, out activity))
>    {
>       //some code to handle the activity...
>    }
> }
Comment 8 kkurz 2016-11-01 22:43:45 UTC
That seems to work. Thanks. The whole translation between multiple languages kills me sometimes.
Comment 9 Sebastien Pouliot 2016-11-02 13:32:53 UTC
Glad it works :)

Keeping open to double check if the value (or others) should be bound.
Comment 10 Sebastien Pouliot 2016-11-11 16:08:42 UTC
castor:xamarin-macios poupou$ grep -r UIApplicationLaunchOptionsUserActivityKey /Applications/Xcode81.app//Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/System/Library/Frameworks/
castor:xamarin-macios poupou$ 

As suspected this is not a "real" constant, where a field must be used, but a normal string for a key. The code from comment #7 is how this should be used.