Recently I’ve been porting a few apps to run in Salesforce1 - typicality these are HTML5 apps that users ran in the device browser and had to log in to each time they wanted to use them, but Salesforce1 avoids that.
As well as porting, I was trying to improve the user experience and make the apps behave consistently if they were running in the browser or inside Salesforce1, and I got caught out a couple of times with behaviour that was either unexpected or something I just couldn’t do. I should stress that these aren’t shortcomings of Salesforce1, its more about how Visualforce pages are displayed inside web view containers.
Pages Opened in the Child Browser don’t have the sforce.one JavaScript object
In a project I was working on recently I had a Visualforce page in Salesforce1 that could be used to open other Visualforce pages. I originally developed this using the sforce.one navigation methods, which opened the relative links in the same page with back buttons etc. Each of these pages relied on the sforce.one JavaScript object being present to provide mobile specific behaviour.
I then refactored this, as I wanted to open in a child browser window so that the user could bounce around a few other pages but retain the close button to jump straight back to the main page. While the sforce.one.navigateToURL() should open absolute URLs in a child browser, even if I specified the target Visualforce page as an absolute URL, the platform appeared to know that it was on the same site and opened it as a relative URL, without using a child browser window.
Relying on my knowledge of the Salesforce mobile SDK, I used the window.open() JavaScript function, which opened the page in the desired fashion, but all of my mobile functionality was broken. After a short amount of digging around it transpired that the sforce.one object was undefined, so as far as my page was concerned it was running on a regular browser.
I’ve put together a couple of pages to demo this. Both pages output some content to describe whether they are running in Salesforce1 or not, and the first page provides a link to the second
Page1:
<apex:page showheader="false" sidebar="false" applyHtmlTag="false" applyBodyTag="false"> <html> <head> <meta name="viewport" content="width=320; initial-scale=1.0; maximum-scale=1.0; user-scalable=0;"></meta> </head> <body> <apex:includeScript value="https://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.9.1.min.js"/> <p style="font-size:24px; text-align:center">Page 1</p> <div style="display:none" id="sf1"> <p style="font-size:20px; text-align:center">I am running in Salesforce1 :)</p> </div> <div style="display:none" id="notsf1"> <p style="font-size:20px; text-align:center">I am not running in Salesforce1 :(</p> </div> <p><a href="javascript:sforce.one.navigateToURL('/apex/SforceDotTwo');">Click to open page two.</a></p> <script> $(document).ready(function () { if ( (typeof sforce != 'undefined') && (sforce != null) ) { $('#sf1').toggle(); } else { $('#notsf1').toggle(); } }); </script> </body> </html> </apex:page>
Page2 :
<apex:page showheader="false" sidebar="false" applyHtmlTag="false" applyBodyTag="false"> <html> <head> <meta name="viewport" content="width=320; initial-scale=1.0; maximum-scale=1.0; user-scalable=0;"></meta> </head> <body> <apex:includeScript value="https://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.9.1.min.js"/> <p style="font-size:24px; text-align:center">Page 2</p> <div style="display:none" id="sf1"> <p style="font-size:20px; text-align:center">I am running in Salesforce1 :)</p> </div> <div style="display:none" id="notsf1"> <p style="font-size:20px; text-align:center">I am not running in Salesforce1 :(</p> </div> <script> $(document).ready(function () { if ( (typeof sforce != 'undefined') && (sforce != null) ) { $('#sf1').toggle(); } else { $('#notsf1').toggle(); } }); </script> </body> </html> </apex:page>
Opening the first page in Salesforce1 displays the “Running in Salesforce1” message as expected:
while clicking the link to go to Page 2 navigates in the same window, including a back button, and displays the message as expected:
Changing the page 2 navigation link to the following:
<p><a href="javascript:window.open('/apex/SforceDotTwo');">Click to open page two.</a></p>
and clicking the link displays the second page in a child browser window (note the close button), but the message has now changed to indicate that the application is not running in Salesforce1:
Accessing external URLs via window.open generates an embedded browser window on a mobile device, with a close button. Don’t use navigation here, as you’ll end up pulling your app into the embedded browser as well as the containing app. When running from the desktop it will open in the same browser window where you would want navigation.
As I was just relying on knowing that I was running in Salesforce1 to style the page and add a few buttons, I could just pass a parameter on the URL to indicate I was running in the application.
HTML5 or Installed Application?
When a Visualforce page is rendered in Salesforce1, there’s no way that I’ve been able to find to determine whether Salesforce1 is the HTML5 web application running in the device’s browser or the installed application. Checking the User Agent for the browser doesn’t help, as they will report the same values based on the device itself.
Update 24/02/2014: The iOS versions of Salesforce1 installed application report a user agent containing the string ‘SalesforceTouchContainer’, so this can be used to determine that the page is running in the installed application. On my Nexus 7, however, the only difference is in the version of Chrome which obviously can’t be relied on to be the same on another Nexus 7, so Android is still problematic. Of course, relying on the user agent is a somewhat flawed approach as applications like the Dolphin web browser allow you to set your own user agent string, but it is the best that we have.
Most of the time I don’t care about this, but I have hit one situation where I wanted to render a particular toolbar button for the installed application but not the HTML5 web application. There is also no concept of a child browser in the HTML5 application - URLs open in the current window or a new tab/window depending on the browser configuration and how the link is constructed.
This isn’t specific to Salesforce1 - it appears to be problematic for Cordova hybrid apps in general, and most of the solutions rely on inspecting the JavaScript window object to see if the cordova object is present, or trying to react to deviceReady events. Unfortunately, as Visualforce is iframed into the Salesforce1 application, all of this information is hidden from my Visualforce page so I ended up reworking my pages to behave in an identical but slightly more clunky fashion in all cases.
If anyone has a solution to this I’d love to hear about it.
I found that the user-agent inside salesforce1 doesn't have the word "Safari" like it has on mobile safari.
ReplyDeleteInspecting html inside salesforce1 app is impossible too, did you find a way to do this?
I open it in chrome on my desktop - using https:///one/one.app - that lets me see my JavaScript errors in all their glory :)
DeleteThe problem here is inspecting the visualforce page in the iPad. I came across several css bugs/errors that happen only inside the salesforce1 app and not in mobile safari :( but thanks for that one
DeleteNelson, you could run Chrome on the iPad.
DeleteI can't prove it by salesforce1 because my android os is 4.1.1, but I've used window.location.href.substr(0,4).toLowerCase() successfully on my personal phonegap apps to detect install (file) vs browser (http).
ReplyDeleteIt seems this is only a 2 step process support for Salesforce1. If we have a VF page, and we want to open another page from here, we should only be using navigateURL() method to redirect it to, becuase if we used window.open() in that page then the lookup fields in second VF page stops working :( ...
ReplyDeleteInclude these files and sforce.one.navigateToURL and the others ought to work.
ReplyDelete"/jslibrary/1408043316000/sfdc/SfdcCore.js"
"/auraFW/javascript/9CWByHqele7x78MwTMyO8g/aura_prod.js"
"/jslibrary/1403810648000/sfdc/AuraAlohaFrameNavigator.js"
"/sforce/one/30.0/api.js"
In salesforce1, on mobile card click it opens the same vf page in full mode.
ReplyDeleteBut if i want to open some other vf page on mobile card click is there any way to do this ??
Can i do this using javascript somehow ??
Hi Bob,
ReplyDeleteDo you have hack over the uper icon of back button. I need to know when this back button press in jquery or javascript.
Please help .
Thanks
Hi Bob,
ReplyDeleteIs there any easy way to detect vf page using salesforce1 or mobile device on server side via apex ?
global static Boolean isMobile() {
DeleteString device = System.currentPageReference().getParameters().get('device');
return (device == 'mobile');
}
Hi Bob
ReplyDeleteIs there a way to prepopulate fields on child VF page? My scenario is: I have a page on Opportunity and upon clicking a link another page opens up - new contact page in edit mode. The problem is I want to prepopulate few fields like account name on contact edit page. PLs help.
Thanks
for me helps incudes this strings:
ReplyDeleteorder is requared
Its not working in Winter16.
ReplyDeleteAnything in particular? There's a few things in the post above.
DeleteHi Bob, Is it mandatory to enable lightening experience to have the sforce.one.navigateToURL(), sforce.one.createRecord() working properly ? In my code i have used something like this in a command link: onclick="javascript:sforce.one.navigateToURL('/00T/e?followup=1&retURL=%2F{!Acc2.id}&tsk5=Call&inline=1'); and it isn't working properly. The navigation is happening in the mobile app, however the full page is not loading. I'm not able to drag the page down or up. It is not dragable or re-sizable. please help
ReplyDeleteNot as far as I'm aware. I don't think URL hacks work in Salesforce1 though.
DeleteHi Bob, I also having the same issue related to URL hack.
ReplyDeleteIn my case, I wants redirect to Report from inline VF page with filter in URL hack using one javascript function:
function RedirectToReportInLE(){
var url = '/00O11000000G4ZN?pc0=00N11000001caDV&pn0=eq&pv0={!LEFT(Account.Id, 15)}&retURL=%2F{!Account.Id}';
sforce.one.navigateToURL(url);
}
This function redirect to right report but filter is missing :(.
I hear a lot about you. Please reply me on above issue ASP. Thanks :)
How can we override back button in SF1?
ReplyDelete