Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Suspend Javascript execution in UIWebView

I am successfuly using an invisible UIWebView as an execution engine for Javascript snippets. Contrary to what certain pages suggest, it does not require to be visible. If declared dead simply as

UIWebView* myJSExecutor = [UIWebView new];

not only it executes any stringByEvaluatingJavaScriptFromString: thrown at it, it even bubbles alert() to the desktop! (Not that it's something you would like to do often) Disclaimer: tested only on iOS 5+

Now, I have another normally visible UIWebView with normal webpage content, and I want it to suspend JavaScript execution: that is stop acting on timer and DOM events. I thought that removeFromSuperview with stopLoading and setting delegate = nil would do the trick. But no, as soon as I add the UIWebView back to some visible view, I can see that the timers were running all the time.

I understand the schizophreny of my requirement. I appreciate it working in the background on one hand (contrary to some observations), but I want to suspend it on the other hand. But still I would like to ask if there is any, perhaps even private way to suspend it. Safari for iOS is capable of suspending browser tabs in the background. Chrome for iOS can't, which may be a sad negative proof :(

like image 880
Pavel Zdenek Avatar asked Feb 12 '26 07:02

Pavel Zdenek


2 Answers

If you're looking for crazy, I have an idea.

The only way I know to pause JavaScript is to show an alert, confirm, prompt, or sending an ajax request with async=false.

Is the alert hidden when the UIWebView is hidden? If so, you could send an alert when you want it to freeze. The user would have to dismiss it when you showed the view again:

[web stringByEvaluatingJavaScriptFromString:@"alert('Press OK to continue...')"];

Or maybe you could dismiss it programmatically. I'm sure you'd agree that this whole suggestion is bound for trouble, but it's a thought.

like image 66
bendytree Avatar answered Feb 13 '26 21:02

bendytree


Do you need a full UIWebView? If not you could just invoke JavaScriptCore directly.

- (NSString *)runJS:(NSString *)aJSString 
{
    JSContextRef ctx = JSGlobalContextCreate(NULL); 
    JSStringRef scriptJS = JSStringCreateWithUTF8CString([aJSString UTF8String]);
    JSValueRef exception = NULL;
    JSValueRef result = JSEvaluateScript([self JSContext], scriptJS, NULL, NULL, 0, &exception); 
    JSGlobalContextRelease(ctx);
    ...

This would give you more control over the entire JS runtime, but unfortunately I've not found an API to suspend execution of timers other than releasing the whole context.

For a more complete example of how to use JavaScriptCore see https://github.com/jfahrenkrug/AddressBookSpy/blob/master/AddressBookSpy/AddressBookSpy/ABSEngine.m

like image 39
MattGoldspink Avatar answered Feb 13 '26 20:02

MattGoldspink



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!