Vukoje's blog about software development

As you probably already know, Salesforce (SF) has built their native app Salesforce1 (SF1) and because SF is such a big hit there is a high chance you app will need to integrate with SF1, which could cause you problems. SF1 is native app which is extendable not by writing native code but by integrating with web apps. Now as native usually means iOS, this integration leads us to dreadful mobile Safari iframe.

The Pain

So here you are, you need to open your app in safari mobile iframe which sucks… and chances are you’ll want to open your existing web app with responsive design that adjusts to mobile screen sizes. Responsive design means general purpose design that adjusts to various screen sizes and as such it is much more complex than pure mobile site. This complexity significantly lowers your chances of working properly in safari mobile iframe.

When I opened my site it was complete agony because it had completely unpredictable behavior. It would reset scroll position in middle of page scrolling and page width would change constantly causing elements to jump around constantly. Occasionally SF1 would crash and wouldn’t open my site again until I reinstalled SF1 app.

I spent few days working on a solution which I wanted to share with everyone and hopefully ease someone’s suffering.

The Solution

In order to fix problem with flickering and iframe width changing I needed to set iframe width to exact value in pixels. Setting width to 100% simply wouldn’t work so I would calculate window width in JavaScript and set it dynamically to iframe.

Now I was left with the problem of scrolling. Unlikely any other browser, mobile Safari iframe expands vertically to display the full document which it contains. There are various strategies for “implementing” iframe scrolling on mobile Safari. At the end I fixed this by setting scrolling="no" and style="overflow: hidden” on iframe. I also set iframe height to window size which I calculated same way as window height. I added this height to iframe url as query string which on the other hand I used to resize my site and actually have scrolling on site instead on iframe.

Maybe you started moving more of your web app logic to client and relying on RESTful services for client-server communication knowing that someday other people will be able to reuse these services as remote API to you app. When I did, I knew that there was a problem with calling restful services from other site’s JavaScript because of the same origin policy that forbids browser to make cross domain Ajax calls, but I also knew that all the major web sites allow restful services consuming from JavaScript.

I investigated a bit and here are alternatives I found for this problem.

JSONP

JSONP is browser hack that became standard solution for cross domain Ajax calls. Browser is hacked by pretending that service is static JavaScript file. In order for this hack to work, server must support JSONP, which means you might be required to alter your services a bit.

Main issue with JSONP is that it doesn’t support HTTP POST (only HTTP GET). Another potential problem with JSONP is that is not asynchronous, which means that it would probably block browser which would lead to poor user experience.

Server Proxy

Another alternative would be to use server proxy that would execute cross-domain request. In other words, do cross-domain request on server instead in browser because server doesn’t have Same-origin policy limitation. The disadvantage is additional work for your clients that must code server proxy instead of consuming your API right from JavaScript.

iFrame integration

Although iFrames have cross domain restrictions like Ajax, they are much more flexible, so hidden iFrame can be used to enable cross-domain Ajax. 3rd party web page could load our special iFrame for that could execute Ajax calls in behalf of 3rd party page because it is on same domain as our API, and then it can send data back to page. For cross origin iFrame communication Window.postMessage can be used or easyXDM library if older browsers need to be supported.