📜 ⬆️ ⬇️

Differences in the adaptation of the site and AJAX web applications for iOS

There is now such a tendency - to support iPad tablets and other devices on iOS in websites: iPhone, iPod. But if it's easy enough for websites, with a good layout, you can add a couple of tags to the head and you're done, for web applications where there are sessions using Cookies , everything is more complicated and there are pitfalls. So, perhaps not everyone knows that in a mobile Safari, you can click the menu button (with an arrow like in the picture) and select “Add to Home” / “Add to Home Screen”, then the icon will appear on the desktop for the site. But the icon will simply launch Safari with this site, but if you add a couple of well-known tags (see below), all Safar controls will be hidden and the application will work on full screen, like regular native iOS applications. So the main problem identified is that in this mode the session is reset all the time . It should switch to another application or desktop, even just follow the link, and again return to the web application, as the page will reload and the session cookie will no longer exist, you need to log in again. Then we will solve this problem.

On good, fullscreen mode is available only for fully dynamic AJAX web applications that do not overload the entire screen and do not follow the links even within their domain. If the usual site is adapted, where navigation takes place when changing the URL and page overload, then fullscreen is not available and the cookies do not disappear.

Recipe for a simple site


This decision is known, I will give it only because I will add the differences for the web application below.
There is documentation on additional Safari meta tags, and here we need meta tags to insert into the head:

<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1"> <link rel="apple-touch-icon-precomposed" href="/favicon.png"> 

The picture /favicon.png will become an icon on your desktop. About the size of the icons written in more detail in the documentation , there may be several, for example.
')

Full screen mode


To switch the application to full screen mode, let's add two more to those two tags:

 <meta name="apple-mobile-web-app-capable" content="yes"> <meta name="apple-mobile-web-app-status-bar-style" content="black" /> 

For a regular site, they have a controversial use, but for a web application it is another matter.

WebApplication Solution


As I casually mentioned, for web applications it is necessary to withstand additional conditions: the application should not follow links a href, this leads to the opening of links in the browser and exit from fullscreen mode. But do window.location.reload(true); you can even window.location = "/demo/path"; completely allowed from javascript. With these transitions cookies are not lost and all is well.

The following code will save the session cookie in localStorage , and when the cookie is lost when switching between applications in iOS, the same code will be restored from the cookie and will reload the page so that the server will give it in the form that the logged in user should receive.

 function PersistCookie(SessionCookieName) { if (localStorage && ( navigator.userAgent.match(/iPhone/i) || navigator.userAgent.match(/iPod/i) || navigator.userAgent.match(/iPad/i) )) { var CookieSession = document.cookie.match(new RegExp(SessionCookieName + "=[^;]+")); var LocalSession = localStorage.getItem(SessionCookieName); if (CookieSession) { CookieSession = CookieSession[0].replace(SessionCookieName + "=", ""); if (LocalSession!=CookieSession) { localStorage.setItem(SessionCookieName, CookieSession); } } else if (LocalSession && LocalSession!=CookieSession) { document.cookie = SessionCookieName + "=" + LocalSession + "; path=/"; window.location.reload(true); } } } 

As can be seen from the code, we have two storage locations for the session variable: document.cookie and localStorage , we read from both, and write where the code was not. If the code is in both places, then document.cookie is preferred, since it may happen that the server replaces the session variable and we need to write it over the one that already exists in localStorage. Call example: PersistCookie ("SID"); The parameters are passed the name of the session cookie. The call must be made when the page is loaded, but it is not necessary to wrap it in an “onload” event or in jQuery.ready (). For PHP, the name of the session cookie is “PHPSESSID”, for ASP.NET “ASP.NET_SessionId”, etc. but may change in the server settings or programmatically. When logging in a user, you need to remember to do if (localStorage) localStorage.clear(); so the cookie does not return. You can also disable the navigator.userAgent check, so that the code works not only in iOS, but I didn’t investigate whether it would be useful or harmful.

PS In general, I found a description of the problem with cookies in the English-language forums, and one timid advice: set the lifetime of the session cookie on the server side. I don’t know why they advised to do this, I tried to do it, the advice doesn’t work, maybe it worked on some older versions of iOS or it only seemed to a person that this method worked. In general, session cookies should not have a lifetime, i.e. Expires according to the specification they do not have , otherwise they cease to be session.

UPD: Found a nice feature, localStorage pass-through for the entire domain, that is, logged into Safari, the session applies to the installed “pseudo-application” and vice versa, if the application logs in, then the safari cookies are added if the page is updated.

UPD2: There is also an unpleasant feature, each time after returning to the “pseudo-application”, besides resetting cookies, the page is also overloaded, that is, if you submit the form and the user starts to fill it, then it switches somewhere, returns and everything is gone, and form and everything you entered. So, even before the post you need to save everything in localStorage. Most likely, you need to make a universal solution for saving forms with any fields, and in general, preserving the “state” of the application at the time of switching, in order to restore what was there. The state can contain the state of navigation within the application, the state of controls (for example, bookmarks, lists), the scrolling state, the state of dynamic changes in html and css on the page. Still dumped half way. By the way, the page is not reloaded from the server when resetting, but taken from the cache.

UPD3: For those who want with minimal effort to make a regular site a pseudo-application in fullscreen mode, but do not have the desire to rewrite everything to AJAX, you can intercept all links and make transitions between pages through window.location. In this case, as already mentioned, Safari will not beat you into browser mode, unless the link will lead to another domain. Here is the jQuery solution:

 $('a').live('click', function(e) { e.preventDefault(); window.location = $(this).attr('href'); }); 

But there is a problem with resetting the site to the first page when switching between applications. It is treated the same way as with cookies - we save it in localStorage. Of course, you need to determine where the links lead and save only links within our domain in localStorage, all others will open in Safari anyway. Here are all the developments collected in the extension for jQuery:

 (function($) { $.platform = { iPhone: navigator.userAgent.match(/iPhone/i), iPod: navigator.userAgent.match(/iPod/i), iPad: navigator.userAgent.match(/iPad/i), Android: navigator.userAgent.match(/Android/i) }; $.platform.iOS = $.platform.iPhone || $.platform.iPod || $.platform.iPad; $.platform.Mobile = $.platform.iOS || $.platform.Android; $.extend({ fixLinks: function(persist) { if ($.platform.iOS) { if (persist == null) persist = true; persist = persist && localStorage; if (persist) { var CurrentLocation = window.location.pathname + window.location.search; var StoredLocation = localStorage.getItem("location"); if (StoredLocation && StoredLocation !== CurrentLocation) { window.location = StoredLocation; } } $('a').live('click',function(e) { e.preventDefault(); if (persist && this.host === window.location.host) localStorage.setItem("location", this.pathname + this.search); window.location = this.href; }); } }, fixCookie: function (SessionCookieName) { if (localStorage && $.platform.iOS) { var CookieSession = document.cookie.match(new RegExp(SessionCookieName + "=[^;]+")); var LocalSession = localStorage.getItem(SessionCookieName); if (CookieSession) { CookieSession = CookieSession[0].replace(SessionCookieName + "=", ""); if (LocalSession!=CookieSession) { localStorage.setItem(SessionCookieName,CookieSession); } } else if (LocalSession && LocalSession !== CookieSession) { document.cookie = SessionCookieName + "=" + LocalSession + "; path=/"; window.location.reload(true); } } } }); })( jQuery ); 

Using the extension is very simple, connect the js file with the library and insert the calls when the page loads:

Source: https://habr.com/ru/post/147563/


All Articles