Implemented an iOS WebBrowserComponent, but

Wow, it’s been a few years since I was last here.

So I have a client who needed a multi-platform web browser extension. Without looking closely at the current JUCE features, I convinced the client that JUCE would cover all platforms needed with minimal code branching. I figured I could write a javascript wrapper around a JUCE browser plugin for Windows and OSX, and then use the plugin component code as the application on iOS and embed a web browser in it. So I did the Windows and OSX versions, and then the iOS version. “Wait a minute! What do you mean iOS WebBrowserComponent is not implemented!” Oops.

After frantically diving into a few Objective-C books, I managed to come up with a working iOS WebBrowserComponent (attached below - just copy over the JUCE source files with the files in the zip).

However, the UIWebView does not pass touch events through to the component peer, which I desperately need. I found this posting which describes a clean method of passing events, and an even simpler method described in the comments:

[quote]krypt responded:
I found more simple way:
just add UITapGestureRecognizer:

UITapGestureRecognizer *tgr = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tap:)]; tgr.delegate = self; [webView addGestureRecognizer:tgr]; [tgr autorelease];
And override message in delegate:

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer { return YES; }[/quote]
My problem is that I am NOT an Objective-C expert and I’ve been floundering trying to figure out how to implement this in the iOS code I wrote (which admittedly I mostly copied and pasted from the JUCE OSX files).

I vaguely understand that I have to add a delegate to webView in the attached file, but I really don’t know how to go about it. Can anyone 'splain to me how I should be doing this (or even take a crack at it yourself)?

ETA [10/03/2011 - 17:55 GMT]: File updated with new code:

Well, I somehow managed to get a delegate working and am now passing a tap gesture to the parent component’s UIView. My next problem is that the mouse event is not propagating to the subclass of the component under the tap (the WebBrowserComponent). In fact, no subclassed members seem to be callable within the context of the tap gesture handler, which is a very strange bug.

You can try this out yourself by creating an application, setting the main component, then add and make visible to it a WebBrowserComponent . You should then call handleTaps() in the WebBrowserComponent class, passing the main component as the target. It’s necessary to do it this way because WebBrowserComponent doesn’t have a UIView peer, so you have to wait until the parent component is fully instantiated and has its own UIView before passing the target. If you then put a breakpoint on UIViewComponentPeer::handleTaps(), you’ll see it trigger when the web page is tapped on, but if you trace to Component::mouseMove(), you’ll see no subclasses are called.

Sorry, I didn’t see your original post. Thanks! I’ll have a play with this soon and get something checked-in - hopefully we can iron out any glitches without too much pain!

This is probably the last update I’ll do for the files. I added in a delegate for the WebBrowserComponent::pageAboutToLoad member callback, so now everything (except for the subclass bug) should be working the same in iOS as on OSX for WebBrowserComponent.

If anyone needs to use this component and wants to get around the subclass bug, you can run a polling loop on Desktop::getMousePosition() to get the current touch position within a web page (remember to subtract the component position offsets). This doesn’t discriminate amongst multiple touches, so keep that in mind when using this version.

[color=#BF0000]Jules[/color]: I didn’t see if the VTables were being loaded into the index registers when I traced through the disassembler. Since I’m a neophyte in Objective-C, I don’t know if the underlying switch from UIWebView to a different UIView in the tap delegate prevents proper loading of VTables.

I’ve checked in a sort of cleaned-up version of this now - didn’t realise how easy it would be or I’d have done it sooner! I’ve added it to the modules branch, and have merged it with the mac browser code to avoid all the code duplication.

I couldn’t really see where you were going with the gesture recogniser stuff, but have added some stubs for it - perhaps have a look at what I’ve done and suggest what you were trying to do… Maybe you meant to have a gesture recogniser added/removed when the component peer changes, which could be done using a ComponentMovementWatcher?

I’m writing a browser-sharing extension that requires a visible indication of where all the share-ees’ mouse pointers are at. On PC and Mac, I just track the mouse position and send that from each connected browser to the other, displaying each user cursor via custom colored cursors. Mobile Safari does not allow extensions, so I have to use an app that displays web pages through UIWebView. UIWebView however does not pass tap positions up to the OS, hence the need for a tap recognizer (which is my substitute for the current mouse position).

So is the WebBrowserComponent supposed to work in iOS? I only see a white rectangle here… (iOS 5, both on iPhone and the simulators).

Did you enable JUCE_WEB_BROWSER?

Yes I did. I just built and ran the equivalent OSX app, and I get a transparent rectangle (i.e. showing the desktop) where the browser is supposed to be. Using 2.0.21 here…

Well, it works just fine for me. Can’t think what else you’d be doing wrong.

Ok, I get the transparent rectangle when I use OpenGL and the white rectangle when not, that much I’ve found out… will keep you posted.

EDIT: solved, apparently you can’t call the getUrl method already in the constructor of the component to which you add the browser, needs to be called a little later then everything’s fine.

EDITEDIT: is a WebBrowserComponent always on top and opaque?

Seems so unfortunately, as it’s a UIView. Hmmm, I was planning to use it to show animated gifs in the background… any other idea how I could achieve this?