Custom URL Scheme & Handling "openURL" Method

Hi everyone.

I’m working on an iOS app that uses a custom URL scheme, and the registration of the scheme is working. The user returns to the app when a URL referencing the scheme is opened.

Now I’m trying to get access to the URL that was used to open the app and any parameters that were passed. To do that, I’m using a custom class for the app itself and implementing the “application:openURL:sourceApplication:annotation:” method.

The “open” event handler of the application class includes this code (to add the method):

if ( not class_addMethod(appDelegateClass, _ NSSelectorFromString("application:openURL:sourceApplication:annotation:"), _ AddressOf implOpenURL, "v@:@:@") ) then break

The class appears to be added successfully - the debugger doesn’t break here. However, the “openURL” event never fires.

The implementation (“implOpenURL”) looks like this:

break enhancediOSApplication(dispatch.Value(pid)).handleOpenURL

Its parameters are defined as:

pid as ptr, openURL as NSURL, sourceApplication as NSString, annotation as NSObject

I suspect that the problem has to do with how I’m defining the params - and specifically how the “annotation” is being defined. According to Apple’s docs for the method (which are available here), the annotation is a “property list object.” I’ve tried defining it as an NSObject, NSArray, etc, without any luck. I’m not exactly sure what the “property list object” really is.

Has anyone else has run into similar issues with “openURL” or successfully implemented it?

Thanks in advance for any help.

~ Tim

Change the params to “pid as ptr, sel as ptr, app as ptr, url as ptr, sourceApp as CFStringRef, annotation as ptr”. Anything that is an NSWhatever is just internally a Xojo pointer so delegate methods like this must just use a pointer for them. The exception is NSString which automatically converts to a CFStringRef which you can then directly assign to a text object.

Also I believe that where you add the method should be changed to this (untested)

if ( not class_addMethod(appDelegateClass, _ NSSelectorFromString("application:openURL:sourceApplication:annotation:"), _ AddressOf implOpenURL, "v@:@@*@") ) then break

Thanks, Jason! I’ve learned a lot from all of the work you’ve been doing (and sharing) with declares. I can’t thank you enough.

I changed the parameters for the implementation method, and how the method is added, and still no luck. The most frustrating aspect of this is that there doesn’t appear to be anything in the console that indicates a problem. It just fails silently.

I have managed to get the “didBecomeActive” method to work properly, and I would use that method to deal with the URL. However, I don’t think it has access to the URL params, and it also occurs much later in the activation sequence.

Anyway, I’ve just uploaded my latest attempt at this. If you get a chance to look at it and have any other thoughts, please let me know. Hopefully this will help others as well. I think that an app’s ability to handle custom URL schemes would open up a lot of possibilities for us.

~ Tim

P.S. To test this little monster, after it loads in the simulator, jump to Safari, and then use one of the supported URL schemes. One is “xojo://” and another is “test://”

I’ll look at it when I can. It will probably end up being Sunday though.

@Tim_Dietrich did you manage to get this working?

The problem you are having is that the selector can (and usually does) fire on a non-main thread. Apple has been moving more and more towards this pattern in their asynchronous user interaction APIs.

So the trick is that in the delegate method you cannot interact with any Xojo objects or framework code. Setting basic types however are fine. Just keep in mind that you can’t call any framework methods to set them either.

Your best bet is to have a timer running that periodically checks a Ptr property to see if it’s non-nil and in your delegate, set that Ptr property with whatever the incoming data is. The technique is similar to the way you avoid having threads access GUI elements.

Or Xojo could properly support pre-emptive threads so we don’t have to rely on hacks like that which don’t work for every async thread use case.

It’s interesting to me how using a timer to poll like this was called a dirty hack 5 years ago but now is the recommended way to do this. Another thing that desperately needs proper support in iOS.

1 Like