Triggering shouldStartLoadWithRequest with multiple window.location.href calls
Asked Answered
S

3

9

Im trying to pass multiple things from a webpage inside a UIWebView back to my iPhone app via the shouldStartLoadWithRequest method of the UIWebView.

Basically my webpage calls window.location.href = "command://foo=bar" and i am able to intercept that in my app no problem. Now if i create a loop and do multiple window.location.href calls at once, then shouldStartLoadWithRequest only appears to get called on once and the call it gets is the very last firing of window.location.href at the end of the loop.

The same thing happens with the webview for Android, only the last window.location.href gets processed.

Softshoe answered 29/5, 2010 at 11:23 Comment(2)
I found a clever solution. Dynamically create an iframe for each command and set its src to "command://foo=bar", you can fire this off multiple times in a loop and shouldStartLoadWithRequest gets called every time! Now to study how to optimize this. I dont think it would be good to create thousands of iframes (even though they are hidden). Any suggestions on that?Softshoe
I would try to optimize every location call as well. If you can only send say 60 calls a minute, then make sure you are jamming every call with enough query vars and fragments to handle multiple commands per call. Also, you might want to check out wkWebView: nshipster.com/wkwebkit it automates much of this process and is more reliable.Gaseous
S
40
iFrame = document.createElement("IFRAME");
iFrame.setAttribute("src", "command://foo=bar");
document.body.appendChild(iFrame); 
iFrame.parentNode.removeChild(iFrame);
iFrame = null;

So this creates an iframe, sets its source to a command im trying to pass to the app, then as soon as its appended to the body shouldStartLoadWithRequest gets called, then we remove the iframe from the body, and set it to null to free up the memory.

I also tested this on an Android webview using shouldOverrideUrlLoading and it also worked properly!

Softshoe answered 29/5, 2010 at 12:24 Comment(5)
This solution is hideously ugly, but it seems to be the least hideously ugly solution possible. It seems Javascript "optimizes" by ignoring window.location calls that are subsequently replaced by other window.location calls. Thank you for saving me from a very painful debugging session!Newcomer
@Newcomer +1 for the hideously ugly, i totally agreeSoftshoe
I want to follow up since i posted this 2 years ago. I wrote an Android and iPhone app that was basically a webview wrapped in a native app. I used this solution so i could communicate from the webview to the native app and its worked flawlessly for the past 2 years i've had over 500k+ downloads of my app.Softshoe
3 year followup, 4,000,000 ios+android downloads combined and this solution has been flawless. Yes it's ugly but it works.Softshoe
You, sir, are brilliant. I've been battling this for hours. Finally the right Google search led me here. Thank you.Dubois
B
3

I struck this problem also and here is my solution that works for me. All my JavaScript functions use this function __js2oc(msg) to pass data and events to Objective-C via shouldStartLoadWithRequest: P.S. replace "command:" with your "appname:" trigger you use.

/* iPhone JS2Objective-C bridge interface */
var __js2oc_wait = 300; // min delay between calls in milliseconds
var __prev_t = 0;
function __js2oc(m) {
  // It's a VERY NARROW Bridge so traffic must be throttled
  var __now = new Date();
  var __curr_t = __now.getTime();
  var __diff_t = __curr_t - __prev_t;
  if (__diff_t > __js2oc_wait) {
    __prev_t = __curr_t;
   window.location.href = "command:" + m;
  } else {
    __prev_t = __curr_t + __js2oc_wait - __diff_t;
    setTimeout( function() {
      window.location.href = "command:" + m;
    }, (__js2oc_wait - __diff_t));
  }
}
Bed answered 29/9, 2011 at 11:59 Comment(0)
E
0

No, iframe's url changing won't trigger shouldOverrideUrlLoading, at least no in Android 2.2.

Etra answered 2/12, 2010 at 7:4 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.