Debugging on-launch Javascript in UIWebView - ios

I'm currently debugging a webpage which is embedded in a UIWebView for display in the app.
It uses some elaborate on-load Javascript which works fine in the Android app but breaks in the iOS app.
This answer pointed me to Safari Web Inspector for UIWebView - however, since the broken Javascript is being run on page load, I can't actually attach the inspector in time to capture whatever's going wrong.
Right now I'm hacking around it by manually inserting a delay into the page, but is there a better way (one that doesn't require I make changes to the page code itself, start the app, rush to load it up in Safari, then wait a while longer for it to continue)?

Important edit: in Safari 7.0, you can reload the page by selecting the "Resources" view, and clicking the refresh arrow next to the top-level page. [It seems you can also do it in at least some versions of Safari 6 by selecting the document tab, clicking the top-level page to select it, and pressing Command+R (the same shortcut used to refresh the page in normal Safari).] Breakpoints you set will still exist if you refresh the page from the Safari Web Inspector, because doing so does not cause SWI to detach the way reloading the page from within your app or the Xcode debugger does. This means that as long as the page doesn't do a Javascript redirect or trigger side-effects in the app itself, you can step through the onload Javascript by loading the page once, setting your breakpoint there, and then reloading the page from within SWI.
Original post: The only solution I was able to find was putting in an "extra" call to shouldStartLoadWithRequest: as follows:
Add a script (not onload, synchronous) as the first element in the page head:
<script type="text/javascript">
window.location = "myapp://catchme";
</script>
Set an XCode breakpoint in shouldStartLoadWithRequest:
Edit the breakpoint to set a condition of:
(bool)[[[request URL] absoluteString] isEqualToString:#"myapp://catchme"]
(Without this condition it will stop on the initial shouldStartLoadWithRequest: call, which isn't what you want because the page won't yet be available to attach the Mobile Web Inspector to at this stage.)
Start the page load, and when it hits the (Xcode) breakpoint, switch to Safari, and launch Mobile Web Inspector with Develop > iPhone Simulator > (my page), then switch back to Xcode and resume execution within a short window before all the resource requests on the page time out.

Weinre helped me to solve this issue, since it's connected right from the start, you get full control of the page.

Why not putting a breakpoint in shouldStartLoadWithRequest and then open the inspector?

Not 100% related to the question OP asked, but I had a similar problem with an Android WebView, in a mobile app whose native code I do not control (but which has WebView debugging enabled).
document.reload() and all other similar means of reloading the page were not working for me
I was thinking to put alert() at the very top of the page, which in theory is a blocking call, but it was not working for me either.
Finally, I went with a blocking, synchronous XHR.
In order to inject an artificial delay when the page is loading, I added a fake call to an endpoint under my control that returns 200 OK after 15 seconds.
Put this at the very top of the <head>
<script>
try {
var request = new XMLHttpRequest();
request.open('GET', 'https://whatever/please-freeze', false); // false = sync XHR
request.send(null);
} catch (err){
debugger;
};
debugger;
</script>
You can for example create your own simple http server with an endpoint behaving like this, but this is a bit of an overkill.
The debugger statements didn't trigger breakpoints in Chrome for whatever reason, but the manually defined breakpoints in the dynamically loaded code (created before) worked fine.
A hack for Windows (Fiddler) users
Since I'm on Windows, I used Fiddler to create an autoresponder with latency.
I also used Fiddler to edit the HTML of the original page request, to inject the <script> mentioned earlier.

Related

MVC IE9 Issue - breakpoints in view not being hit

I have a weird problem on my site that only happens in IE9 - I have some js code that I need to add to the page but only for IE9 as it is to sort out the placeholders. However the code is not getting added and I don't know if this is a bug with IE9 or MVC.
The problem is that I put the code for the script at the top of the view - it gets added to a session which then gets rendered on the master template, but in IE9, the view is not being hit so the code doesn't get rendered. I have put a breakpoint onto the view and visited the page in all the browsers. The breakpoint gets hit and then moves onto the master layout in every browser except IE9 where the breakpoint is completely missed (no matter where I put it in the view) and the master layout is loaded first.
However if I do a postback on this page, the view will then be hit and the script will render.
Has anyone had this problem before or know what causes it
Update
the code in the controller isn't hit in IE9 either. Is this a caching problem - if so, how do I stop MVC caching a page
Okay, a further update is in IE9, I have noticed that the url being loaded is http://localhost/Quote/#/Quote/Form/ but in every other browser the url is the correct one: http://localhost/Quote/Form/. If I go to the correct url then the page works properly in IE9.
Is this caused by jQuery mobile ajax enabled option?
The error was caused by the # being added to the url. I found that if I entered the following code just before the jQuery mobile script:
<script type="text/javascript">
$(document).on("mobileinit", function () {
$.mobile.ajaxEnabled = #Html.Raw(Request.Browser.IsMobileDevice ? "true" : "false");
});
</script>
It solved my problem

jQuery Mobile on Android: page load

I have a web application that runs just fine on Android until I started to use jQM. It still runs fine with jQM on the desktop...
The problem is that when I load a "new URL" using "window.location.href = newLocation;" the new page loads fine the first time but the next time the page is displayed ok but then disappears and I can just see the header and footer of the first page (not the second). When I refresh I see the second page ok. Another way to have it working is to always refresh the first page b4 launching the second.
I have tried to disable page transition and Ajax but with no success.
If I run (I guess it is stupid):
$.mobile.changePage(newLocation, { transition: "none"});
window.location.href = newLocation;
it always works but then I sometimes get "Error loading page".
Any ideas? $.mobile.changePage(newLocation, { transition: "none"}); alone does not work...
Here is a "bypass" solution. It works but there may be better ones...
First I tried to add some JS to force a reload of the first page when coming back from the second but no JS executed...
Then I saw After travelling back in Firefox history, JavaScript won't run and just added "window.onunload = function(){};" to the first page. This prevents caching of the first page and now things are working.
It looks like page caching was causing the problem but I don't know why this means that jQM fails...

Binding to pageinit event generates a white page with spinner

I'm binding to the jQuery Mobile pageinit event to do some additional stuff after a page has been created/enhanced and loaded into the DOM (per the docs) like so:
$('#home').live('pageinit', function()
{
...
};
But, all I'm getting is a white spinner and the page never displays on an iOS device running OS6. It works fine in the simulator. What could I be doing wrong?
There are plenty of references to pageinit not working if placed in the wrong part of the page, though generally that wouldn't cause the page to stop loading.
A script error in the event handler (the ... part) could cause the symptoms described, but would likely work the same in the simulator.
Are you sure all the files are referenced correctly? Unlike OSX, iOS is case sensitive, so a reference to jQuery.js instead of jquery.js will cause problems that you can't see anywhere else. You should be able to connect the desktop safari web inspector to the app to find any load errors.

grails - how to view resulting page source javascript, when it is updated via Ajax via rendering of a template, for example

If one uses remoteFunction or one of the the Grails Ajax capabilities, rendering a template to update a portion of a page, how does one see any additions made to the Javascript functions associated with the resulting page in Chrome or Firefox?
In Chrome, one is able to see the updated page/DOM via going to their Tools -> Developer Tools menu item, then selecting "Elements". There, I'm able to use the magnifying glass to select a portion of the updated page that I want to see. But, how do I also see the additional Javascript functions added to the page.
NOTE: Originally this question requested to see both html element content and Javascript content. Karthick AK's answer handles both.
In Chrome->Developer tool-> Network tab,
For each request being sent the response obtained can be seen in the Response tab. The rendered content can be seen in here.
Similiar option exists for firefox/firebug.
Another ajax gotcha i have experienced is, sometimes the ajax requests are cached and hence onclick the content is served from the cache and not an actual requests hits the server. This is more prominant in Old IE browsers

How can I load iOS webclip links in the same window?

After loading up a Webclip with some links in it, clicking a link launches Mobile Safari instead of loading the link in the same window. Is there a way to prevent the link loading in Safari instead of the Webclip instance? I'm trying to mock up a mobile app just using PHP on my local Apache installation.
According to the Apple docs it looks like external page links will always open in Mobile Safari:
In this mode any external links will be opened in Safari on
iPhone, meaning that you will have to keep your web application to a
single page and use Ajax to update parts of that page.
In addition to the option of using a single page loading new content with AJAX, you can use the JavaScript self.location=URL; return false on hyperlinks that must stay within the application. This can be added to the HTML code directly, or with another script upon loading the page.
If you are using jQuery, I would recommend something like this:
$('a:not([target])').click(function(){
self.location = $(this).attr('href');
return false;
});
Obviously this script should be ran after the HTML has loaded, to ensure that it actually attaches to the A elements onClick event.

Resources