Like many independent software vendors, the CircleBack team was eagerly anticipating the launch of the Salesforce1 platform. As a mobile app developer, Salesforce’s massive investment behind a mobile platform was perfectly aligned with our products. However, we faced a unique challenge—at least compared with other partners who were selected to develop integrations prior to Dreamforce ’13—we had a feature-rich, native iOS app that could not be re-architected into HTML5, allowing it to run inside the Salesforce1 environment. This post details three of the technical challenges we faced and how they were addressed.

Use Case

ScanBizCards is a mobile application for—you guessed it—scanning business cards with your mobile phone.We’ve had Salesforce integration for a while now, allowing a user to export a scanned card as a Contact or Lead into their Salesforce org directly from the app. They do this using the Salesforce API. When we heard about Salesforce1, the use case seemed obvious: A Salesforce1 user would import a new Contact or Lead into Salesforce1, and thus into their Salesforce org, by way of our mobile app.


We had already developed what we call the “side-by-side” integration model for our app. The model allowed it to be invoked by—and then return scanned card data to—other native apps or mobile websites. This was accomplished using iOS’s custom URL protocols.

In our case, an external app or website could invoke ScanBizCards using the scanbizcards:// protocol (with various parameters to control app behavior and tell the app where to send the contact data after the scan was complete). Our integration point within Salesforce1 was to create a Global Action which manifested as a tile called “Scan Business Card” in the actions menu. The tile opens when a user touches the big plus (+) button in the bottom right corner of the Salesforce1 home screen.

Challenge #1: Invoking ScanBizCards

Touching our tile in the actions menu would invoke a Visualforce page we created. The goal was to redirect the user from this Visualforce page to the scanbizcards:// protocol automatically. This redirection would ideally be automatic and instantaneous since there was no real content we cared to display in the Visualforce page at that point. Essentially, the user would touch the “Scan Business Card” tile and the ScanBizCards app would open. Since Visualforce pages in Salesforce1 are essentially mobile web pages, there were a few familiar candidates for performing the redirect. After experimenting with <meta https-equiv=”refresh”> and <apex:iframe> tags, the solution that served our needs best was one of the special Salesforce1 JavaScript methods: A full discussion of the pros & cons of each approach is beyond the scope of this post, but numerous factors were considered such as reliability, speed, and the state of the Salesforce1 app when control is eventually returned to it.

Challenge #2: Detection of Native App

A related challenge that presented itself was how to deal with the scenario of the ScanBizCards app not being installed on the user’s device at the time when we attempt to redirect the user from Salesforce1. The ability to detect the presence of a native app on the user’s device from a mobile web page—which is the equivalent challenge of detecting it from Visualforce within Salesforce1—is a much lamented deficit in iOS throughout the developer community.

Attempting to redirect the user to a custom URL protocol for an app that is not installed yields an ugly alert, which isn’t particularly informative to the user. There is no way around this alert, but there are a few JavaScript-based approaches that seek to recognize the scenario after the fact. The cleverest one involves recording the current time, setting a timer to fire in a few seconds, and immediately attempting the redirect. In the code that fires as a result of the timer, you check the current time and compare to the time you recorded earlier. If the difference is the length of the timer (i.e. you recorded time 0, set a timer for 3 seconds, and then in the timer’s handler you see time=3), then you can assume the user did not have the app installed and can take appropriate action (such as showing a link to download the app from the App Store). If, however, the amount of time elapsed is far longer than the length of the timer, it means the redirect succeeded, and JavaScript execution on the Visualforce page was suspended. In that case, you could instead show a message appropriate for when the user is returned to Salesforce1 after your native app has done whatever it does.

Challenge #3: Returning Control to Salesforce1 After the Scan

The last leg of the journey was for the ScanBizCards app to return the user to Salesforce1 after scanning the business card. Ordinarily in our “side-by-side” integrations, we pass the scanned contact data back to the calling app as a query string, appended to that app’s custom URL protocol. We expect the calling app to have expressly coded support for receiving contact data in this way. Salesforce1’s custom URL protocol (the vestigial chatter://) had no such support. To work around this, we perform the export of the scanned data within ScanBizCards using our usual Salesforce API calls. Then, we return the user to Salesforce1 by redirecting to chatter://. Since this brings the user back to the Salesforce1 home page (which shows their news feed), we also post an item to the user’s news feed with a link to the recently exported Lead or Contact. This shows the result of the user’s actions within ScanBizCards.


Despite a few sub-optimal bumps in the process—notably the inability to detect whether the user has the app installed or not—integrating Salesforce1 with a native mobile app is fairly easy. It can be a great way to align your native app with Salesforce1’s new, robust mobile platform.

Want to see how the ScanBizCards app turned out with SalesForce integration? You can download the iOS version in Apple’s iTunes Store. An updated Android version will be in the Google Play store soon!

Download ScanBizCards for iOS (Lite)

Download ScanBizCards for iOS (Premium)