# developer Mobile SDK Development Guide (mobile-sdk) - Full Documentation # About Backbone Technology The Mobile Sync library, `mobilesync.js`, provides extensions to the open-source Backbone JavaScript library. The Backbone library defines key building blocks for structuring your web application: - Models with key-value binding and custom events, for modeling your information - Collections with a rich API of enumerable functions, for containing your data sets - Views with declarative event handling, for displaying information in your models - A router for controlling navigation between views Salesforce Mobile Sync extends the `Model` and `Collection` core Backbone objects to connect them to the Salesforce REST API. Mobile Sync also provides optional offline support through SmartStore, the secure storage component of the Mobile SDK. To learn more about Backbone, see [http://backbonejs.org/](http://backbonejs.org/). You can also search online for “backbone javascript” to find tutorials and videos. # About Hybrid Development JavaScript development in a browser is straightforward. After you’ve altered the code, you merely refresh the browser to see your changes. Developing hybrid apps with the Mobile SDK container requires you to recompile and rebuild after you make changes. For this reason, we recommend you develop your hybrid app directly in a browser, and only run your code in the container in the final stages of testing. We recommend developing in a browser such as Google Chrome that comes bundled with developer tools. These tools let you access the symbols and code of your web application during runtime. Mobile SDK JavaScript libraries give you a choice to code with traditional callback functions: ```nolang traditionalCallbackMethod(args, onSuccess, onFailure) ``` or using promises: ```javascript promiseBasedMethod(args).then(onSuccess).catch(onFailure); ``` Using the callback function, you can write: ```javascript self.smartstoreClient.removeSoup(soupName, onSuccessRemoveSoup(soupName), onErrorRemoveSoup(soupName)); ... function onSuccessRemoveSoup(name) {…} function onErrorRemoveSoup(name) {…} ``` Promises help you keep your asynchonous code inline, making it easier to follow. Using the promise function, you can rewrite the callback code like this: ```javascript self.smartstoreClient.removeSoup(soupName) .then(function(soupName) { ... }) .catch(function(soupName) { ... }) ``` # About Login and Passcodes To access Salesforce objects from a Mobile SDK app, the customer logs in to a Salesforce org. When the login flow begins, Mobile SDK sends the app’s external client app or connected app configuration to Salesforce. Salesforce responds by posting a login screen to the mobile device. Optionally, a Salesforce administrator can set the external client app or connected app to require a passcode after login. This setting, for example, requires a backgrounded app to prompt for a passcode when it returns to the foreground. When the external client app or connected app requires a mobile app passcode, Mobile SDK 9.2 and later use the device system passcode. To verify a required passcode, Mobile SDK presents a lock screen that uses the customer’s configured verification mode—for example, touch ID, face ID, or direct passcode entry. If no device passcode has been set, Mobile SDK prompts the customer to visit the iOS Settings interface and create one. If the external client app or connected app doesn’t require a mobile passcode, Mobile SDK skips the passcode verification step. Mobile SDK handles all login and passcode lock screens and the authentication handshake. ## Mobile Passcode Policies Each Mobile SDK app hard-codes an external client app or connected app’s consumer key and OAuth callback URL from a specific Salesforce org. Mobile SDK honors the configurable passcode requirement in that org’s designated external client app or connected app. Beginning in version 9.2, Mobile SDK ignores org settings such as PIN length, and instead relies on device configuration. Similarly, incorrect passcode entries are handled according to the standard procedure of the mobile operating system. **note:** Beginning in version 9.2, Mobile SDK ignored the **Lock App After** setting in the org’s Connected App, in favor of the device’s configuration for locking the device after it’s been idle. In version 10.1.1 and later, Mobile SDK again respects the **Lock App After** Connected App setting. When set, the mobile app locks after it has been in the background for longer than the timeout period. Locking occurs when the mobile app is activated. Unlocking the app remains the same. If a customer uses the app to log into a different org, Mobile SDK can’t retrieve the designated external client app or connected app settings. Therefore, that customer never encounters the passcode prompt. ## Multi-User Behavior of the Lock Screen When multiple users are logged into the same app on the same device, the lock screen behaves as follows. 1. When resuming an app that requires passcode, the customer is first prompted by a lock screen to authenticate through the mobile operating system. 2. If the customer cancels authentication, **Logout** and **Retry Unlock** buttons appear on the lock screen. 3. The **Logout** button works only for customers that require the lock screen. 4. If the last user that requires the lock screen logs out, Mobile SDK no longer shows the lock screen. ## Using Biometric Identification By default, Mobile SDK supports the use of Touch ID and Face ID for passcode verification. Customers can set their preference for biometric or any other iOS input mode in Settings. Biometric identification requires the following app configuration. - App Configuration - : 1. Open your app’s information property list (plist) file. 2. Add the following top-level property: - Key: **NSFaceIDUsageDescription** (labeled “Privacy - Face ID Usage Description”) - Value: **\<_Enter any string_>** (for example, “Use Face ID to avoid retyping your PIN”) ![Face ID configuration in the app's plist](https://developer.salesforce.com/docs/media/face_id_plist_config.png) ## Disabling Biometric Identification Apps built with Mobile SDK 9.2 and later ignore biometric settings from Salesforce external client apps or connected apps. Instead, customers can configure the authentication mode themselves in device settings. ## See Also - [About PIN Security](https://developer.salesforce.com/docs/platform/mobile-sdk/guide/connected-apps-security-pin.md) - [OAuth 2.0 Authentication Flow](https://developer.salesforce.com/docs/platform/mobile-sdk/guide/oauth-intro-flow.md) - [Biometric Authentication](https://developer.salesforce.com/docs/platform/mobile-sdk/guide/biometric-auth.md) # About Multi-User Support Beginning in version 2.2, Mobile SDK supports simultaneous logins from multiple user accounts. These accounts can represent different users from the same organization, or different users on different organizations (such as production and sandbox, for instance.) Once a user signs in, that user’s credentials are saved to allow seamless switching between accounts, without the need to re-authenticate against the server. If you don’t wish to support multiple logins, you don’t have to change your app. Existing Mobile SDK APIs work as before in the single-user scenario. Mobile SDK assumes that each user account is unrelated to any other authenticated user account. Accordingly, Mobile SDK isolates data associated with each account from that of all others, thus preventing the mixing of data between accounts. Data isolation protects `SharedPreferences` files, SmartStore databases, `AccountManager` data, and any other flat files associated with an account. ## Example For native Android, the `RestExplorer` sample app demonstrates multi-user switching: For native iOS, the `RestAPIExplorer` sample app demonstrates multi-user switching: The following hybrid sample apps demonstrate multi-user switching: - **Without SmartStore:** `ContactExplorer` - **With SmartStore:** `AccountEditor` # About Native, HTML, and Hybrid Development Salesforce Mobile SDK gives you options for developing your app. You can choose the options that fit your development skills, device and technology requirements, goals, and schedule. With Mobile SDK, you can choose the development platform that best fits your business needs and resources. These platforms include: - Native - HTML Living Standard - Hybrid - React Native Each platform option supports both iOS and Android. Use the following descriptions to get a sense of which option best suits your requirements. ## Native Apps Native apps are specific to a given mobile platform (iOS or Android). These apps use the development tools and languages that the respective platform supports. For example, you develop iOS apps in Xcode using Swift or Objective-C. Of all app types, native apps look and perform best. They provide the best usability, the best features, and the best overall mobile experience. For example, native is the best choice for delivering the following features: - **Fast graphics API**—The native platform gives you the fastest graphics. This advantage helps, for example, if you’re using large quantities of data and require a fast refresh. - **Fluid animation**—Related to the fast graphics API is the ability to have fluid animation. This ability is especially important in mobile apps for UI graphics and video streaming. - **Built-in components**—The camera, contacts, geolocation, and other features native to the device can be seamlessly integrated into mobile apps. Another important built-in component is encrypted storage. - **Ease of use**—The native platform is what people are accustomed to. When you add that familiarity to the native features they expect, your app becomes that much easier to use. Native app development requires an integrated development environment (IDE). IDEs provide rich platform-specific tools for building and debugging code, project management, version control, and other necessities. While the required level of experience is higher than for other development scenarios, the levels of control and freedom are also higher. Other benefits of native development can include: - Proven APIs and frameworks give you confidence that your efforts are worthwhile - Established components that define standard behaviors like navigation, tabs, and modal dialogs - Source control that allows you to maintain all your code in one secure place ## HTML Apps HTML apps (also known as HTML5 apps) use standard web technologies—typically the HTML Living Standard, JavaScript, and CSS—to deliver web pages to a mobile browser. Getting started with ubiquitous HTML standards and tools is easier than adopting native compilers or hybrid frameworks. HTML development creates multi-platform mobile apps that are device agnostic and can run on any modern mobile browser. Responsive web design automatically adapts your content to various screen sizes and resolutions, thus reducing your testing requirements. The HTML “write once, run anywhere” approach minimizes distribution efforts: Push a bug fix or new feature to the production server, and it’s instantly available to all users. And because your content is on the web, it’s search enabled—a major benefit for many types of apps. If HTML apps are easy to develop and support and can reach a wide range of devices, what are the drawbacks? - **No secure offline storage**—HTML browsers support offline databases and caching, but with no standard encryption support. Mobile SDK offers all of these features. - **Unfriendly security flows**—Trivial security measures can pose complex implementation challenges in mobile web apps. They can also be painful for users. For example, some web apps with authentication require users to reenter their credentials every time the app restarts or returns from a background state. - **Limited native features**—Support for camera, contacts, and other native features can vary, especially among older mobile browsers. - **Lack of native look and feel**—HTML can only emulate the native look, and customers can’t use familiar compound gestures. ## Hybrid Apps Hybrid apps combine the ease of HTML coding with the power of the native platform. The resulting application can access the device’s native capabilities and is distributed through the App Store. You can also create hybrid apps that deliver Lightning web components or Visualforce pages. Hybrid apps wrap HTML, JavaScript, and CSS code inside a lightweight native container that provides access to native platform features. Generally, hybrid apps provide the best of both HTML and native worlds. They’re almost as easy to develop as HTML apps and access native functionality through JavaScript APIs. In addition, hybrid apps can use the Mobile SDK offline features to - Model, query, search, and edit Salesforce data. - Securely cache Salesforce data for offline use. - Synchronize locally cached data with the Salesforce server. Unlike HTML apps, hybrid apps are downloaded and installed on mobile devices. Perhaps you’re wondering whether hybrid apps store their files on the device or on a server. Great question! The storage location depends on whether the hybrid app is local or remote. - Local - : You can package HTML and JavaScript code inside the mobile application binary, in a structure similar to a native application. You use REST APIs and Ajax to move data back and forth between the device and the cloud. - Remote - : Alternatively, you can implement the full web application from the server (with optional caching for better performance). Your container app retrieves the full application from the server and displays it in a native web view. In addition, hybrid remote apps can host Lightning web components. Hybrid is the only Mobile SDK platform that currently supports these popular Salesforce entities. ## React Native Apps React Native apps use the React Native framework from Facebook, Inc., to run JavaScript apps as native code. Rather than following the hybrid paradigm, React Native lets you assemble the native UI building blocks with JavaScript code. This framework provides direct access to native resources and lets you test without recompiling. In performance terms, React Native runs a close second to pure native execution. React Native apps use specialized scripting languages. - JavaScript is ES2015. - CSS is JavaScript code that closely resembles CSS syntax and is typically written inline in your JavaScript app. - Markup is actually a special flavor of XML named JSX. Unlike HTML, which embeds JavaScript in markup, you embed JSX markup in JavaScript. - TypeScript support lets you use non-binding static typing in your JavaScript code. In addition, React Native bridges provide access to standard Mobile SDK features, such as: - SmartStore - Mobile Sync - Salesforce login and authentication - Salesforce REST API access. You can even access your own native objects—in Swift, Objective-C, or Java—directly in React Native code. ## Mobile Architecture Comparison The following table shows how the various development scenarios stack up. |   | Native, React Native | HTML | Hybrid | | ----------------------------------- | ----------------------------------------------------------------------------------- | ---------------------------------------- | --------------------------------------------------------- | | **Graphics** | Native APIs | HTML, Canvas, SVG | HTML, SVG | | **Performance** | Fastest | Fast | Moderately fast | | **Look and feel** | Native | Emulated | Emulated | | **Distribution** | App Store, Google Play | Web | App Store, Google Play | | **Camera** | Yes | Browser dependent | Yes | | **Notifications (from Salesforce)** | Yes | No | Yes | | **Contacts, calendar** | Yes | Browser dependent | Yes | | **Offline storage** | Secure file system | Not secure; shared SQL, Key-Value stores | Secure file system; shared SQL (through Cordova plug-ins) | | **Geolocation** | Yes | Yes | Yes | | **Swipe** | Yes | Yes | Yes | | **Pinch, spread** | Yes | Yes | Yes | | **Connectivity** | Online, offline | Mostly online | Online, offline | | **Development skills** | Swift, Objective-C, Java, Kotlin; JavaScript/TypeScript, markup (React Native only) | HTML, CSS, JavaScript | HTML, CSS, JavaScript | # About PIN Security Beginning in version 9.2, Mobile SDK uses the mobile device PIN instead of an app-specific PIN and simplifies the passcode flow. - For iOS, see [About Login and Passcodes](https://developer.salesforce.com/docs/platform/mobile-sdk/guide/ios-native-login-passcodes.md). - For Android, see [Using Passcodes](https://developer.salesforce.com/docs/platform/mobile-sdk/guide/android-passcodes.md). # About Push Notifications With the Salesforce notification service, you can develop and test push notifications in Mobile SDK custom apps. Mobile SDK provides APIs that you can implement to register devices with the push notification service. However, receiving and handling the notifications remain the responsibility of the developer. Setup to receive push notification occurs on several levels: - Configuring push services from the device technology provider (Apple for iOS, Google for Android) - Configuring your Salesforce external client app or connected app definition to enable push notifications - Configuring the Salesforce org to send push notifications to your app through one or more of these methods: - Implementing Apex triggers - Subscribing to Notification Builder custom notification types and pushing those notifications through Process Builder, Flow Builder, or the Connect REST API - Calling the push notification resource of the Connect REST API - Making minor code changes to support registration in your Mobile SDK app - Implementing a class extension to support decryption in iOS apps - Registering the mobile device at runtime You’re responsible for Apple or Google service configuration, external client app or connected app configuration, Apex or Connect REST API coding, and minor changes to your Mobile SDK app. Salesforce Mobile SDK handles runtime registration transparently. For information on setting up mobile push notifications for your organization and creating your own custom notifications tray, see the [Mobile Notifications Implementation Guide](https://developer.salesforce.com/docs/atlas.en-us.pushImplGuide.meta/pushImplGuide/pns_overview.htm). # About Salesforce Mobile Apps The Salesforce Platform offers two ways to build and deploy enterprise-ready mobile applications. - The Salesforce mobile app, available on App Store and Google Play Store, is the fastest way for Salesforce administrators and developers to deliver apps for employees. It offers simple point-and-click tools for administrators and the Lightning web development platform for advanced developers. - Salesforce Mobile SDK gives developers the tools to build custom mobile apps with unique user experiences. Mobile SDK lets you produce standalone custom apps that you distribute through the App Store or Google Play Store. These apps can target employees, customers, or partners. You can choose native or web technologies to build these apps while enjoying the same grade of reliability and security found in the Salesforce mobile app. Mobile SDK offers the following features: - **Enterprise Identity & Security** - : Mobile SDK implements Salesforce login and authentication flows for you. It includes a complete implementation of Salesforce Connected App Policy, so that all users can access their data securely and easily. It supports SAML and advanced authentication flows so that administrators always have full control over data access. - **SmartStore Encrypted Database** - : Mobile databases are useful for building highly responsive apps that also work in any network condition. SmartStore provides an easy way to store and retrieve data locally while supporting a flexible data model. It uses AES-256 encryption to ensure that your data is always protected. - **Mobile Sync** - : Mobile Sync provides a simple API for synchronizing data between your offline database and the Salesforce cloud. With Mobile Sync, developers can focus on the UI and business logic of their application while leaving the complex synchronization logic to Mobile SDK. - **Mobile Services** - : Mobile SDK supports a wide range of platform mobile services, including push notifications, geolocation, analytics, collaboration tools, and business logic in the cloud. These services can supercharge your mobile application and also reduce development time. - **Salesforce Communities** - : With Salesforce Communities and Mobile SDK, developers can build mobile applications that target their customers and partners. These applications benefit from the same enterprise features and reliability as employee apps. - **iOS and Android** - : Mobile SDK supports native development on the two dominant mobile operating systems. - Hybrid and React Native - : For JavaScript developers, Mobile SDK offers Cordova-based hybrid apps and React Native apps. These apps access the Mobile SDK libraries through native containers. # About SmartStore SmartStore provides the primary features of non-relational desktop databases—data segmentation, indexing, querying—along with caching for offline storage. **important:** Where possible, we changed noninclusive terms to align with our company value of Equality. We maintained certain terms to avoid any effect on customer implementations. ## What’s New in SmartStore Smart SQL no longer requires index paths for all fields referenced in SELECT or WHERE clauses This improvement doesn’t extend to soups that use external storage. ## About Data Caching To provide offline synchronization and conflict resolution services, SmartStore uses StoreCache, a Mobile SDK caching mechanism. We recommend that you use StoreCache to manage operations on Salesforce data. **note:** Pure HTML5 apps store offline information in a browser cache. Browser caching isn’t part of Mobile SDK, and we don’t document it here. SmartStore uses storage functionality on the device. This strategy requires a native or hybrid development path. ## About the Sample Code Objective-C code snippets in this chapter use Account and Opportunity objects, which are predefined in every Salesforce organization. Accounts and opportunities are linked through a master-detail relationship. An account can be the master for more than one opportunity. **See Also** - [Using StoreCache For Offline Caching](https://developer.salesforce.com/docs/platform/mobile-sdk/guide/entity-framework-using-storecache.md) - [Conflict Detection](https://developer.salesforce.com/docs/platform/mobile-sdk/guide/entity-framework-conflict-detection.md) - [Smart SQL Queries](https://developer.salesforce.com/docs/platform/mobile-sdk/guide/offline-smart-sql.md) # About Sync Statuses To enable full control over “in-flight” sync operations, Mobile SDK 7.1 adds a new status that indicates that the operation has been stopped. Before Mobile SDK 7.1, each sync operation progressed through a cycle of statuses: `new`, `running`, and either `failed` or `done`. Mobile SDK 7.1 adds a `stopped` status to the final step, changing the cycle as follows: 1. `new` 2. `running` 3. `stopped` | `failed` | `done` When key events occur, sync statuses are updated as follows. | Event | Previous Status | Reported Status | | --------------------------------------------------------------------------------------------------------------- | ------------------- | --------------- | | App creates a sync object | — | new | | Sync object is submitted for running by a call to a sync down or sync up method, or by a first call to `reSync` | new | running | | Sync operation completes successfully | running | done | | Sync operation fails to complete | running | failed | | A sync manager stop request is detected | running | stopped | | Sync manager restarts with the `restartStoppedSyncs` parameter set to true | stopped | running | | `reSync` is called | stopped/failed/done | running | ![Flow chart showing how sync status changes at key events](https://developer.salesforce.com/docs/media/sync-status-flow.png) **note:** - Any call to a `reSync` method on a currently running sync operation fails. - Any call to a `reSync`, `syncDown`, `syncUp`, or `cleanResyncGhosts` method fails if the sync manager state is not in the `accepting_syncs` state. - If any sync operations are running when the sync manager is first initialized—for example, if the app recently crashed shortly after starting syncs—the sync manager sets their statuses to `stopped`. ## Getting Sync Objects by Status Beginning with Mobile SDK 7.1, sync manager objects support a `getSyncsWithStatus` method that returns all sync state objects whose status matches a given value. You can use this method, for example, to iterate through all stopped syncs and restart them manually. **note:** To assume manual restart control over stopped syncs, call the sync manager’s `restart` method with `restartStoppedSyncs` set to false. **iOS** - Swift - : ```nolang open class func getSyncsWithStatus(_ store: , status: SyncStatus) -> [SyncState] ``` - Objective-C - : ```nolang + (NSArray) getSyncsWithStatus:(SFSmartStore*)store status:(SFSyncStateStatus)status; ``` **Android (Java)** ```nolang public static List getSyncsWithStatus( store, Status status) ``` # About Sync Targets Sync targets configure data transfers between the Salesforce cloud and a local database on a mobile device. Mobile SDK 5.1 enhances the capabilities of targets to give developers more control over two-way data synchronization. Mobile Sync is all about syncing data. In essence, it - Syncs data _down_ from the server to a local database, and - Syncs data _up_ from the local database to the server. Often, the data you’re transferring doesn’t cross break any rules, and the default sync targets work fine. For special cases, though, you can provide your own sync target to make sure that data transfers occur as expected. An example is when an object contains fields that are required but that apps can’t update. If a sync up operation tries to upload both new and updated records with a single field list, the operation fails if it tries to update locked fields. Beginning in Mobile SDK 5.1, you have other options that can often spare you from implementing a custom target. ## Decentralizing Sync Manager Tasks (Or, Power to the Custom Targets!) In the first Mobile Sync release, the sync manager class internally handled all server and local database interactions. In addition, the sync manager was a “final” class that was off-limits for developer customization. Developers were unable to add their own nuances or extended functionality. Later, an architectural refactoring delegated all server interactions from the sync manager class to sync down and sync up target classes. Thus began a transfer of power from the monolithic sync manager to the flexible sync targets. Unlike sync manager class, the second-generation target classes let developers subclass sync targets for their own purposes. By controlling interactions with servers, custom sync targets can talk to arbitrary server endpoints, or transform data before storing it. Mobile SDK 5.1 enhances Mobile Sync still further by moving local database interactions into targets. This enhancement offers several benefits. - It decouples Mobile Sync from SmartStore, giving developers the freedom to use other stores. - It allows developers to use their own data layouts and capture local data changes however they like. - It enables more complex objects, such as targets that can simultaneously handle multiple record types. In short, Mobile Sync now offers developers significant control over the entire round trip of data synchronization. **note:** Beginning in Mobile SDK 5.1, additional “sync up” options can sometimes obviate the need for a custom target. See [Defining a Custom Sync Up Target](https://developer.salesforce.com/docs/platform/mobile-sdk/guide/entity-framework-native-up-target-def.md). # About Sync Task Errors In Mobile SDK 7.1 and later, sync task methods return error information consistently across platforms. Sync tasks—sync down, sync up, resync, and clean resync ghosts—can fail for the following reasons: - Invalid ID or name - The requested sync operation is already running - Sync manager is stopped or stopping To inform apps of the nature of failures, sync methods in Mobile SDK 7.1 and later return error information as follows. - On iOS: - Swift methods throw a `SyncState` object. - Objective-C methods include an `NSError**` parameter. Earlier versions of these methods are deprecated. - On Android, these methods throw `MobileSyncException`. ## New and Updated Sync and Resync Methods in Mobile SDK 7.1 ### New iOS Methods - Objective-C - : The following methods now support and `NSError` parameter. ```nolang - (nullable SFSyncState*) syncDownWithTarget:(SFSyncDownTarget*)target options:(SFSyncOptions*)options soupName:(NSString*)soupName syncName:(*nullable* NSString*)syncName updateBlock:(SFSyncSyncManagerUpdateBlock)updateBlock error:(NSError**)error ; - (*nullable* SFSyncState*) syncUpWithTarget:(SFSyncUpTarget*)target options:(SFSyncOptions*)options soupName:(NSString*)soupName syncName:(*nullable* NSString*)syncName updateBlock:(SFSyncSyncManagerUpdateBlock)updateBlock error:(NSError**)error; - (*nullable* SFSyncState*) reSync:(NSNumber*)syncId updateBlock:(SFSyncSyncManagerUpdateBlock)updateBlock error:(NSError**) error; - (*nullable* SFSyncState*) reSyncByName:(NSString*)syncName updateBlock:(SFSyncSyncManagerUpdateBlock)updateBlock error:(NSError**)error NS_SWIFT_NAME(reSync(named:onUpdate:)); ``` ### Updated iOS Methods - Swift - : The following methods now throw a `SyncState` object. ```nolang open func syncDown(target: SyncDownTarget, options: SyncOptions, soupName: String, syncName: String?, onUpdate updateBlock: @escaping SyncUpdateBlock) throws -> SyncState open func syncUp(target: SyncUpTarget, options: SyncOptions, soupName: String, syncName: String?, onUpdate updateBlock: @escaping SyncUpdateBlock) throws -> SyncState open func reSync(id syncId: NSNumber, onUpdate updateBlock: @escaping SyncUpdateBlock) throws -> SyncState open func reSync( named syncName: String, onUpdate updateBlock: @escaping SyncUpdateBlock) throws -> SyncState ``` ## Deprecated iOS Methods in Mobile SDK 7.1 - Objective-C - : Existing sync methods that do not support an `NSError` output parameter are slated for removal in a future major release. ```nolang - (nullable SFSyncState*) syncDownWithTarget:(SFSyncDownTarget*)target options:(SFSyncOptions*)options soupName:(NSString*)soupName syncName:(*nullable* NSString*)syncName updateBlock:(SFSyncSyncManagerUpdateBlock)updateBlock; - (nullable SFSyncState*) syncUpWithTarget:(SFSyncUpTarget*)target options:(SFSyncOptions*)options soupName:(NSString*)soupName syncName:(*nullable* NSString*)syncName updateBlock:(SFSyncSyncManagerUpdateBlock)updateBlock; - (nullable SFSyncState*) reSync:(NSNumber*)syncId updateBlock:(SFSyncSyncManagerUpdateBlock)updateBlock; - (nullable SFSyncState*) reSyncByName:(NSString*)syncName updateBlock:(SFSyncSyncManagerUpdateBlock)updateBlock; ``` ## See Also For changes to `cleanResyncGhosts` methods, see [Handling “Ghost” Records After Sync Down Operations](https://developer.salesforce.com/docs/platform/mobile-sdk/guide/entity-framework-sync-ghosts.md). # About This Guide This guide introduces you to Salesforce Mobile SDK and teaches you how to design, develop, and manage mobile applications for the cloud. Topics cover all platforms supported by Mobile SDK, including - Native iOS - Native Android - React Native - Cordova-based hybrid - HTML and JavaScript ## Intended Audience This guide is primarily for developers who are already familiar with mobile technology, OAuth2, and REST APIs. It’s most easily accessible to developers who have some Salesforce Platform experience. If that doesn’t exactly describe you, though, don’t worry. We provide resources both for beginners and for more advanced developers. For example, perhaps you're a Salesforce admin who’s developing your first mobile app, or an experienced mobile developer who’s new to Salesforce technology. We encourage beginners to start with our Mobile SDK Trailhead modules. Afterwards, you can consult this guide as needed for expanding your knowledge. Here are the Mobile SDK trails: - [_Develop with Mobile SDK_](https://trailhead.salesforce.com/content/learn/trails/mobile_sdk_intro) - : Introduces all supported platforms—iOS, Android, hybrid, and React Native—and surveys Mobile SDK offline features. - [_Modern Mobile Development with iOS_](https://trailhead.salesforce.com/content/learn/modules/modern-mobile-development-ios) - : Augments the iOS beginner trail with Xcode and Swift basics plus more advanced Mobile SDK tutorials. Shorter, less formal tutorials are scattered throughout this guide. # Accessing Custom API Endpoints In Mobile SDK 2.1, Mobile Sync expands its scope to let you work with any REST API. Previously, you could only perform basic operations on sObjects with the Salesforce Platform API. Now you can use Mobile Sync with Apex REST objects, Chatter Files, and any other Salesforce REST API.  You can also call non-Salesforce REST APIs. # Accessing Salesforce Data: Controllers vs. APIs In an HTML5 app, you can access Salesforce data two ways. - By using JavaScript remoting to invoke your Apex controller. - By accessing the Salesforce API with `force.js`. ## Using JavaScript Remoting to Invoke Your Apex Controller Apex supports the following two means of invoking Apex controller methods from JavaScript: - [`apex:actionFunction`](https://developer.salesforce.com/docs/atlas.en-us.pages.meta/pages/pages_compref_actionFunction.htm) - [JavaScript remoting](https://developer.salesforce.com/docs/atlas.en-us.pages.meta/pages/pages_js_remoting.htm) Both techniques use an AJAX request to invoke Apex controller methods directly from JavaScript. The JavaScript code must be hosted on a Visualforce page. In comparison to `apex:actionFunction`, JavaScript remoting offers several advantages. - It offers greater flexibility and better performance than `apex:actionFunction`. - It supports parameters and return types in the Apex controller method, with automatic mapping between Apex and JavaScript types. - It uses an asynchronous processing model with callbacks. - Unlike `apex:actionFunction`, the AJAX request does not include the view state for the Visualforce page. This results in a faster round trip. Compared to `apex:actionFunction`, however, JavaScript remoting requires you to write more code. The following example inserts JavaScript code in a \

Hello, Visualforce!

Welcome to Mobile SDK.

``` **note:** - Using the REST API—even from a Visualforce page—consumes API calls. - Salesforce API calls made through a Mobile SDK container or through a Cordova webview do not require proxy services. Cordova webviews disable same-origin policy, so you can make API calls directly. This exemption applies to all Mobile SDK hybrid and native apps. ## Additional Options You can use the Mobile Sync in HTML5 apps. Just include the required JavaScript libraries as static resources. Take advantage of the model and routing features. Offline access is disabled for this use case. See [Using Mobile Sync to Access Salesforce Objects](https://developer.salesforce.com/docs/platform/mobile-sdk/guide/entity-framework-intro.md). ## Offline Limitations Read these articles for tips on using HTML5 with Salesforce Platform offline. - [https://developer.salesforce.com/blogs/developer-relations/2011/06/using-html5-offline-with-forcecom.html](https://developer.salesforce.com/blogs/developer-relations/2011/06/using-html5-offline-with-forcecom.html) - [https://developer.salesforce.com/blogs/developer-relations/2013/03/using-javascript-with-force-com.html](https://developer.salesforce.com/blogs/developer-relations/2013/03/using-javascript-with-force-com.html) # Account Editor Sample Account Editor is the most complex Mobile Sync-based sample application in Mobile SDK 2.0. It allows you to create/edit/update/delete accounts online and offline, and also demonstrates conflict detection. To run the sample: 1. If you’ve made changes to `external/shared/sampleApps/mobilesync/bootconfig.json`, revert it to its original content. 2. Launch Account Editor. This application contains three screens: - Accounts search - Accounts detail - Sync When the application first starts, you see the Accounts search screen listing the most recently used accounts. In this screen, you can: - Type a search string to find accounts whose names contain the given string. - Tap an account to launch the account detail screen. - Tap **Create** to launch an empty account detail screen. - Tap **Online** to go offline. If you are already offline, you can tap the **Offline** button to go back online. (You can also go offline by putting the device in airplane mode.) To launch the Account Detail screen, tap an account record in the Accounts search screen. The detail screen shows you the fields in the selected account. In this screen, you can: - Tap a field to change its value. - Tap **Save** to update or create the account. If validation errors occur, the fields with problems are highlighted. If you’re online while saving and the server’s record changed since the last fetch, you receive warnings for the fields that changed remotely. Two additional buttons, **Merge** and **Overwrite**, let you control how the app saves your changes. If you tap **Overwrite,** the app saves to the server all values currently displayed on your screen. If you tap **Merge**, the app saves to the server only the fields you changed, while keeping changes on the server in fields you did not change. - Tap **Delete** to delete the account. - Tap **Online** to go offline, or tap **Offline** to go online. To see the Sync screen, tap **Online** to go offline, then create, update, or delete an account. When you tap **Offline** again to go back online, the Sync screen shows all accounts that you modified on the device. Tap **Process _n_ records** to try to save your local changes to the server. If any account fails to save, it remains in the list with a notation that it failed to sync. You can tap any account in the list to edit it further or, in the case of a locally deleted record, to undelete it. ## Looking Under the Hood To view the source code for this sample, open `AccountEditor.html` in an HTML or text editor. Here are the key sections of the file: - Script includes - Templates - Models - Views - Router ## Script Includes This sample includes the standard list of libraries for Mobile Sync applications. - jQuery—See [http://jquery.com/](http://jquery.com/). - Underscore—Utility-belt library for JavaScript, required by backbone. See [http://underscorejs.org/](http://underscorejs.org/). - Backbone—Gives structure to web applications. Used by Mobile Sync. See [http://backbonejs.org/](http://backbonejs.org/). - `cordova.js`—Required for hybrid applications using the Salesforce Mobile SDK. - `force.js`—Salesforce Platform JavaScript library for making REST API calls. Required by Mobile Sync. - `mobilesync.js`—Mobile Sync. - `fastclick.js`—Library used to eliminate the 300 ms delay between physical tap and firing of a click event. See [https://github.com/ftlabs/fastclick](https://github.com/ftlabs/fastclick). - `stackrouter.js` and `auth.js`—Helper JavaScript libraries used by all three sample applications. ## Templates Templates for this application include: - search-page - sync-page - account-list-item - edit-account-page (for the Account detail page) ## Models This sample defines three models: `AccountCollection`, `Account` and `OfflineTracker`. `AccountCollection` is a subclass of Mobile Sync’s `Force.SObjectCollection` class, which is a subclass of the Backbone framework’s `Collection` class. The `AccountCollection.config()` method returns an appropriate query to the collection. The query mode can be: - Most recently used (MRU) if you are online and haven’t provided query criteria - SOQL if you are online and have provided query criteria - SmartSQL when you are offline When the app calls `fetch()` on the collection, the `fetch()` function executes the query returned by `config()`. It then uses the results of this query to populate `AccountCollection` with Account objects from either the offline cache or the server. `AccountCollection` uses the two global caches set up by the AccountEditor application: `app.cache` for offline storage, and `app.cacheForOriginals` for conflict detection. The code shows that the `AccountCollection` model: - Contains objects of the `app.models.Account` model (`model` field) - Specifies a list of fields to be queried (`fieldlist` field) - Uses the sample app’s global offline cache (`cache` field) - Uses the sample app’s global conflict detection cache (`cacheForOriginals` field) - Defines a `config()` function to handle online as well as offline queries Here’s the code (shortened for readability): ```javascript app.models.AccountCollection = Force.SObjectCollection.extend({ model: app.models.Account, fieldlist: ["Id", "Name", "Industry", "Phone", "Owner.Name", "LastModifiedBy.Name", "LastModifiedDate",], cache: function () { return app.cache;}, cacheForOriginals: function () { return app.cacheForOriginals;}, config: function () { // Offline: do a cache query if (!app.offlineTracker.get("isOnline")) { // ... } // Online else { // ... } }, }); ``` `Account` is a subclass of Mobile Sync’s `Force.SObject` class, which is a subclass of the Backbone framework’s `Model` class. Code for the `Account` model shows that it: - Uses a `sobjectType` field to indicate which type of sObject it represents (Account, in this case). - Defines `fieldlist` as a method rather than a field, because the fields that it retrieves from the server are not the same as the ones it sends to the server. - Uses the sample app’s global offline cache (`cache` field). - Uses the sample app’s global conflict detection cache (`cacheForOriginals` field). - Supports a `cacheMode()` method that returns a value indicating how to handle caching based on the current offline status. Here’s the code: ```javascript app.models.Account = Force.SObject.extend({ sobjectType: "Account", fieldlist: function (method) { return method == "read" ? ["Id", "Name", "Industry", "Phone", "Owner.Name", "LastModifiedBy.Name", "LastModifiedDate"] : ["Id", "Name", "Industry", "Phone"]; }, cache: function () { return app.cache;}, cacheForOriginals: function () { return app.cacheForOriginals;}, cacheMode: function (method) { if (!app.offlineTracker.get("isOnline")) { return Force.CACHE_MODE.CACHE_ONLY; } // Online else { return method == "read" ? Force.CACHE_MODE.CACHE_FIRST : Force.CACHE_MODE.SERVER_FIRST; } } }); ``` `OfflineTracker` is a subclass of Backbone’s `Model` class. This class tracks the offline status of the application by observing the browser’s offline status. It automatically switches the app to offline when it detects that the browser is offline. However, it goes online only when the user requests it. Here’s the code: ```javascript app.models.OfflineTracker = Backbone.Model.extend({ initialize: function () { var that = this; this.set("isOnline", navigator.onLine); document.addEventListener("offline", function () { console.log("Received OFFLINE event"); that.set("isOnline", false); }, false,); document.addEventListener("online", function () { console.log("Received ONLINE event"); // User decides when to go back online }, false,); } }); ``` ## Views This sample defines five views: - SearchPage - AccountListView - AccountListItemView - EditAccountView - SyncPage A view typically provides a template field to specify its design template, an `initialize()` function, and a `render()` function. Each view can also define an `events` field. This field contains an array whose key/value entries specify the event type and the event handler function name. Entries use the following format: ```nolang "[ ]": "" ``` For example: ```nolang events: { "click .button-prev": "goBack", "change": "change", "click .save": "save", "click .merge": "saveMerge", "click .overwrite": "saveOverwrite", "click .toggleDelete": "toggleDelete" }, ``` - SearchPage - : View for the entire search screen. It expects an `AccountCollection` as its model. It watches the search input field for changes (the `keyup` event) and updates the model accordingly in the `search()` function. ```nolang events: { "keyup .search-key": "search" }, search: function(event) { this.model.setCriteria($(".search-key", this.el).val()); this.model.fetch(); } ``` - AcountListView - : View for the list portion of the search screen. It expects an `AccountCollection` as its model and creates `AccountListItemView` object for each account in the `AccountCollection` object. - AccountListItemView - : View for an item within the list. - EditAccountPage - : View for account detail page. This view monitors several events: | Event Type | Target Control | Handler function name | | ---------- | --------------------------------- | --------------------- | | click | button-prev | goBack | | change | Not set (can be any edit control) | change | | click | save | save | | click | merge | saveMerge | | click | overwrite | saveOverwrite | | click | toggleDelete | toggleDelete | A couple of event handler functions deserve special attention. The `change()` function shows how the view uses the event target to send user edits back to the model: ```nolang change: function(evt) { // apply change to model var target = event.target; this.model.set(target.name, target.value); $("#account" + target.name + "Error", this.el).hide(); } ``` The `toggleDelete()` function handles a toggle that lets the user delete or undelete an account. If the user clicks to undelete, the code sets an internal `__locally_deleted__ flag` to false to indicate that the record is no longer deleted in the cache. Else, it attempts to delete the record on the server by destroying the local model. ```nolang toggleDelete: function() { if (this.model.get("__locally_deleted__")) { this.model.set("__locally_deleted__", false); this.model.save(null, this.getSaveOptions( null, Force.CACHE_MODE.CACHE_ONLY)); } else { this.model.destroy({ success: function(data) { app.router.navigate("#", {trigger:true}); }, error: function(data, err, options) { var error = new Force.Error(err); alert("Failed to delete account: " + (error.type === "RestError" ? error.details[0].message : "Remote change detected - delete aborted")); } }); } } ``` - SyncPage - : View for the sync page. This view monitors several events: | Event Type | Control | Handler function name | | ---------- | ----------- | --------------------- | | click | button-prev | goBack | | click | sync | sync | To see how the screen is rendered, look at the render method: ```javascript render: function(eventName) { $(this.el).html(this.template(_.extend( {countLocallyModified: this.model.length}, this.model.toJSON()))); this.listView.setElement($("ul", this.el)).render(); return this; }, ``` Let’s take a look at what happens when the user taps **Process** (the sync control). The `sync()` function looks at the first locally modified Account in the view’s collection and tries to save it to the server. If the save succeeds and there are no more locally modified records, the app navigates back to the search screen. Otherwise, the app marks the account as having failed locally and then calls `sync()` again. ```nolang sync: function(event) { var that = this; if (this.model.length == 0 || this.model.at(0).get("__sync_failed__")) { // We push sync failures back to the end of the list. // If we encounter one, it means we are done. return; } else { var record = this.model.shift(); var options = { mergeMode: Force.MERGE_MODE.MERGE_FAIL_IF_CHANGED, success: function() { if (that.model.length == 0) { app.router.navigate("#", {trigger:true}); } else { that.sync(); } }, error: function() { record = record.set("__sync_failed__", true); that.model.push(record); that.sync(); } }; return record.get("__locally_deleted__") ? record.destroy(options) : record.save(null, options); } }); ``` ## Router When the router is initialized, it sets up the two global caches used throughout the sample. ```nolang setupCaches: function() { // Cache for offline support app.cache = new Force.StoreCache("accounts", [ {path:"Name", type:"string"} ]); // Cache for conflict detection app.cacheForOriginals = new Force.StoreCache("original-accounts"); return $.when(app.cache.init(), app.cacheForOriginals.init()); }, ``` Once the global caches are set up, it also sets up two `AccountCollection` objects: One for the search screen, and one for the sync screen. ```nolang // Collection behind search screen app.searchResults = new app.models.AccountCollection(); // Collection behind sync screen app.localAccounts = new app.models.AccountCollection(); app.localAccounts.config = { type:"cache", cacheQuery: { queryType:"exact", indexPath:"__local__", matchKey:true, order:"ascending", pageSize:25}}; ``` Finally, it creates the view objects for the Search, Sync, and EditAccount screens. ```nolang // We keep a single instance of SearchPage / SyncPage and EditAccountPage app.searchPage = new app.views.SearchPage({model: app.searchResults}); app.syncPage = new app.views.SyncPage({model: app.localAccounts}); app.editPage = new app.views.EditAccountPage(); ``` The router has a `routes` field that maps actions to methods on the router class. ```nolang routes: { "": "list", "list": "list", "add": "addAccount", "edit/accounts/:id": "editAccount", "sync":"sync" }, ``` The `list` action fills the search result collections by calling `fetch()` and brings the search page into view. ```nolang list: function() { app.searchResults.fetch(); // Show page right away - list will redraw when data comes in this.slidePage(app.searchPage); }, ``` The `addAccount` action creates an empty account object and bring the edit page for that account into view. ```nolang addAccount: function() { app.editPage.model = new app.models.Account({Id: null}); this.slidePage(app.editPage); }, ``` The `editAccount` action fetches the specified Account object and brings the account detail page into view. ```nolang editAccount: function(id) { var that = this; var account = new app.models.Account({Id: id}); account.fetch({ success: function(data) { app.editPage.model = account; that.slidePage(app.editPage); }, error: function() { alert("Failed to get record for edit"); } }); } ``` The sync action computes the `localAccounts` collection by calling fetch and brings the sync page into view. ```nolang sync: function() { app.localAccounts.fetch(); // Show page right away - list will redraw when data comes in this.slidePage(app.syncPage); } ``` # AccountSwitcherActivity Class Use or extend the `AccountSwitcherActivity` class to display the user switching interface. The `AccountSwitcherActivity` class provides the screen that handles multi-user logins. It displays a list of existing user accounts and lets the user switch between existing accounts or sign into a new account. To enable multi-user logins, launch the activity from somewhere in your app using the following code: ```java final Intent i = new Intent(this, SalesforceSDKManager.getInstance(). getAccountSwitcherActivityClass()); i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); this.startActivity(i); ``` For instance, you might launch this activity from a “Switch User” button in your user interface. See `SampleApps/RestExplorer` for an example. If you like, you can customize and stylize `AccountSwitcherActivity` through XML. For more control, you can extend `AccountSwitcherActivity` and replace it with your own custom sub-class. To replace the default class, call `SalesforceSDKManager.setAccountSwitcherActivityClass()`. Pass in a reference to the class file of your replacement activity class, such as `AccountSwitcherActivity.class`. # Add Mobile SDK Libraries to Your Project **important:** Where possible, we changed noninclusive terms to align with our company value of Equality. We maintained certain terms to avoid any effect on customer implementations. ## Prerequisites 1. [Create an Xcode Swift Project](https://developer.salesforce.com/docs/platform/mobile-sdk/guide/ios-new-native-manual-create-xcode-project.md) ## Add the Mobile SDK Swift Package For general instructions on adding package dependencies to your app, see Apple’s documentation: [Adding package dependencies to your app](https://developer.apple.com/documentation/xcode/adding-package-dependencies-to-your-app). To add the Mobile SDK Swift package, use these configurations in Xcode. - Package repository URL: [https://github.com/forcedotcom/SalesforceMobileSDK-iOS-SPM](https://github.com/forcedotcom/SalesforceMobileSDK-iOS-SPM). - Version: 11.0.1 (or any version thereafter). # Add Permissions to a Profile Create a profile that has API Enabled and Enable Chatter permissions. 1. From Setup, enter `Profiles` in the Quick Find box, then select **Profiles**. 2. Click **New Profile**. 3. For Existing Profile select **Customer Community User**. 4. For **Profile Name** type `FineApps API User`. 5. Click **Save**. 6. On the FineApps API User page, click **Edit**. 7. For **Administrative Permissions** select **API Enabled** and **Enable Chatter**. **note:** A user who doesn’t have the Enable Chatter permission gets an insufficient privileges error immediately after successfully logging into your Experience Cloud site in Salesforce. 8. Click **Save**. **note:** In this tutorial we use a profile, but you can also use a permission set that includes the required permissions. # Add the API User Profile To Your Experience Cloud Site Add the API User profile to your Experience Cloud site setup on the Members page. 1. Click **Administration** | **Members**. 2. For Search, select **All**. 3. Select **FineApps API User** in the Available Profiles list and then click **Add**. 4. Click **Save**. 5. Click **Publish**. 6. Dismiss the confirmation dialog box and click **Close**. # Add the Search Result List Item View To define the search result list item view, you design and implement the view of a single row in a list. Each list item displays the following user fields: - SmallPhotoUrl - FirstName - LastName - Title 1. Immediately after the `UserListView` view definition, create the view for the search result list item. Once again, extend `Backbone.View` and indicate that this view is a list item by defining the `tagName` member. For the remainder of this procedure, add all code in the `extend({})` block. ```javascript app.views.UserListItemView = Backbone.View.extend({}); ``` 2. Add an `
  • ` tag. ```javascript app.views.UserListItemView = Backbone.View.extend({ tagName: "li", }); ``` 3. Load the template by calling `_.template()` with the raw content of the `user-list-item` script. ```javascript template: _.template($("#user-list-item").html()), ``` 4. Add a `render()` function. The `template()` function, from `underscore.js`, takes JSON data and returns HTML crafted from the associated template. In this case, the function extracts the customer’s data from JSON and returns HTML that conforms to the `user-list-item` template. During the conversion to HTML, the `template()` function replaces free variables in the template with corresponding properties from the JSON data. ```javascript render: function(eventName) { $(this.el).html(this.template(this.model.toJSON())); return this; }, ``` 5. Add a `close()` method to be called from the list view that does necessary cleanup and stops memory leaks. ```javascript close: function() { this.remove(); this.off(); } ``` ## Example Here’s the complete extension. ```javascript app.views.UserListItemView = Backbone.View.extend({ tagName: "li", template: _.template($("#user-list-item").html()), render: function (eventName) { $(this.el).html(this.template(this.model.toJSON())); return this; }, close: function () { this.remove(); this.off(); }, }); ``` # Add the Search Result List View The view for the search result list doesn’t need a template. It is simply a container for list item views. It tracks these views in the `listItemViews` member. If the underlying collection changes, it re-renders itself. 1. In the ` ``` ## Example Here’s the complete model code. ```javascript ``` # Create a New Contact and User Instead of creating users directly, create a contact on an account and then create the user from that contact. If you don’t currently have any accounts, 1. Click the **Accounts** tab. 2. If your org doesn’t yet contain any accounts: 1. In Quick Create, enter `My Test Account` for **Account Name**. 2. Click **Save**. 3. In Recent Accounts click **My Test Account** or any other account name. Note the Account Owner’s name. 4. From Setup, enter `Users` in the Quick Find box, select **Users**, and then click **Edit** next to your Account Owner’s name. 5. Make sure that **Role** is set to a management role, such as CEO. 6. Click **Save**. 7. Click the **Accounts** tab and again click the account’s name. 8. In Contacts, click **New Contact**. 9. Fill in the following information: First Name: `Jim`, Last Name: `Parker`. Click **Save**. 10. On the Contact page for Jim Parker, click **Manage External User** and then select **Enable Customer User**. 11. For User License select **Customer Community**. 12. For Profile select the FineApps API User. 13. Use the following values for the other required fields: | Field | Value | | -------- | -------------------------------------- | | Email | Enter your active valid email address. | | Username | `jimparker@fineapps.com` | | Nickname | `jimmyp` | You can remove any non-required information if it’s automatically filled in by the browser. 14. Click **Save**. 15. Wait for an email to arrive in your inbox welcoming Jim Parker and then click the link in the email to create a password. Set the password to “mobile333”. # Create a Template Project First, make sure you’ve installed Salesforce Mobile SDK using the NPM installer. For iOS instructions, see [iOS Preparation](https://developer.salesforce.com/docs/platform/mobile-sdk/guide/install-ios.md). For Android instructions, see [Android Preparation](https://developer.salesforce.com/docs/platform/mobile-sdk/guide/install-android.md). Also, download the `ratchet.css` file from [http://goratchet.com/](http://goratchet.com/). Once you’ve installed Mobile SDK, create a local hybrid project for your platform. 1. At a Terminal window or Windows command prompt, run the `forcehybrid create` command using the following values: | Prompt (or Parameter) | Value | | -------------------------------- | ----------------------------------------------------------------------------------------------- | | Platform (`--platform`) | `ios`, `android`, or `ios,android` | | Application type (`--apptype`) | `hybrid_local` | | Application name (`--appname`) | `UserSearch` | | Package name (`--packagename`) | `com.acme.usersearch` | | Organization (`--organization`) | `“Acme Widgets, Inc.”` | | Output directory (`--outputdir`) | Leave blank for current directory, or enter a name to create a new subdirectory for the project | Here’s a command line example: ```nolang forcehybrid create --platform=ios,android --apptype=hybrid_local --appname=UserSearch --packagename=com.acme.usersearch --organization="Acme Widgets, Inc." --outputdir="" ``` 2. Copy all files—actual and symbolic—from the `samples/usersearch` directory of the [https://github.com/forcedotcom/SalesforceMobileSDK-Shared/](https://github.com/forcedotcom/SalesforceMobileSDK-Shared) repository into the `www/` folder, as follows: - In a Mac OS X terminal window, change to your project’s root directory—./UserSearch/—and type this command: ```nolang cp -RL /samples/UserSearch/* www/ ``` - In Windows, make sure that every file referenced in the `<*shared repo*>\samples\usersearch` folder also appears in your `<*project_name*>\www` folder. Resolve the symbolic links explicitly, as shown in the following script: ```nolang cd set SHARED_REPO= copy %SHARED_REPO%\samples\usersearch\UserSearch.html www copy %SHARED_REPO%\samples\usersearch\bootconfig.json www copy %SHARED_REPO%\dependencies\ratchet\ratchet.css www copy %SHARED_REPO%\samples\common\styles.css www copy %SHARED_REPO%\test\MockCordova.js www copy %SHARED_REPO%\samples\common\auth.js www copy %SHARED_REPO%\dependencies\backbone\backbone-min.js www copy %SHARED_REPO%\libs\cordova.force.js www copy %SHARED_REPO%\dependencies\fastclick\fastclick.js www copy %SHARED_REPO%\libs\ www copy %SHARED_REPO%\libs\force+promise.js www copy %SHARED_REPO%\dependencies\jquery\jquery.min.js www copy %SHARED_REPO%\libs\ www copy %SHARED_REPO%\samples\common\stackrouter.js www copy %SHARED_REPO%\dependencies\underscore\underscore-min.js www ``` 3. Run the following command: ```nolang cordova prepare ``` 4. Open the `platforms/android/` project folder in Android Studio (for Android) or Xcode (for iOS) by following the onscreen instructions printed by forcehybrid. 5. From the `www` folder, open `UserSearch.html` in your code editor and delete all its contents. # Create an Experience Cloud Site Create an Experience Cloud site and a site login URL. The following steps are fully documented at [Enable Digital Experiences](https://help.salesforce.com/apex/HTViewHelpDoc?id=networks_enable.htm) and [Create an Experience Cloud Site](https://help.salesforce.com/apex/HTViewHelpDoc?id=networks_creating.htm) in Salesforce Help. 1. In Setup, enter `digital experiences` in the Quick Find box. 2. If you don’t see **All Sites**: 1. Click **Settings**. 2. Select **Enable digital experiences**. 3. Enter a unique name for your domain name, such as `fineapps..force.com` for **Domain name**. 4. Click **Check Availability** to make sure the domain name isn’t already being used. 5. Click **Save**. 3. From Setup, enter `digital experiences` in the Quick Find box, then select **All Sites**. 4. Click **New Site**. 5. Choose a template and name the new Experience Cloud site `FineApps Users`. 6. For **URL**, type `customers` in the suffix edit box. The full URL shown, including your suffix, becomes the new URL for your Experience Cloud site. 7. Click **Create Site**. # Create an External Client App External client apps are the new generation of connected apps, designed to improve security and solve packaging and distribution issues that affect connected apps. **note:** Connected apps creation is restricted as of Spring ‘26. You can continue to use existing connected apps during and after Spring ‘26. However, we recommend using external client apps instead. If you must continue creating connected apps, contact Salesforce Support. See [New connected apps can no longer be created in Spring ‘26](https://help.salesforce.com/s/articleView?id=005228017&type=1) for more details. If you have an existing local connected app, migrate your app by following the directions in [Create an External Client App from a Connected App](https://help.salesforce.com/s/articleView?id=xcloud.migrate_connected_app_to_external_client_app.htm&type=5). A Salesforce administrator creates external client apps on the Salesforce server. Salesforce external client apps include many settings that are used only by other mobile offerings such as the Salesforce app. The following steps cover the settings that apply to Mobile SDK apps. To create an external client app: 1. From Setup, in the Quick Find box, enter **App Manager**, and then select **App Manager**. 2. Click **New External Client App**. 3. Under **Basic Information**, fill out the form as follows: - **External Client App Name**: (whatever you like; can contain spaces) - **API Name**: accept the suggested value - **Contact Email**: enter your email address - **Distribution State**: To develop an external client app for your local org, select **Local**. To develop an external client app for packaging and distribution, set the Distribution State to **Packaged**. 4. Under **API (Enable OAuth Settings)**, check **Enable OAuth Settings**. 5. Set **Callback URL** to any URL string, real or fictional, such as `mysampleapp://auth/success`. If autofill offers a suggestion, do not accept it. Instead, type in the callback URL. 6. Under **Available OAuth Scopes**, select: - Access the identity URL service (`id`, `profile`, `email`, `address`, `phone`) - Manage user data via APIs (`api`) - Manage user data via Web browsers (`web`) - Perform requests at any time (`refresh_token`, `offline_access`) - (Optional) Access the Salesforce API Platform (`sfap_api`) - (Optional) Access chatbot services (`chatbot_api`) 7. Click **Add**. This set of scopes works well for most Mobile SDK apps. 8. Under **Security**: - Uncheck **Require Secret for Web Server Flow**. - Uncheck **Require Secret for Refresh Token Flow**. - (Recommended) Check **Issue JSON Web Token (JWT)-based access tokens for named users**. 9. Click **Create**. ## Configure an External Client App’s Push Notification Settings To configure an ECA’s push notification settings, see: - [Configure the External Client App’s Push Notification Settings and Policies for iOS](https://help.salesforce.com/s/articleView?id=xcloud.configure_external_client_app_push_notifications_ios.htm&type=5) - [Configure the External Client App’s Push Notification Settings and Policies for Android](https://help.salesforce.com/s/articleView?id=xcloud.configure_external_client_app_push_notifications_android.htm&type=5) ## See Also - _Salesforce Help_: [Create an External Client App](https://help.salesforce.com/s/articleView?id=xcloud.connected_app_create.htm&type=5) - _Salesforce Help_: [Comparison of Connected Apps and External Client Apps Features](https://help.salesforce.com/s/articleView?id=xcloud.connected_apps_and_external_client_apps_features.htm&type=5) - _Salesforce Help_: [Create an External Client App from a Connected App](https://help.salesforce.com/s/articleView?id=xcloud.migrate_connected_app_to_external_client_app.htm&type=5) # Create an Xcode Swift Project **important:** Where possible, we changed noninclusive terms to align with our company value of Equality. We maintained certain terms to avoid any effect on customer implementations. ## Summary of Steps In Xcode, create an **App** project that uses **Swift** language, the **SwiftUI** interface, and the **UIKit App Delegate** life cycle. ## Create an Empty Xcode Project—Details 1. In Xcode, select **File** | **New** | **Project**. Or, from the Xcode Welcome screen, select **Create a new Xcode project**. 2. On the iOS tab, select **App**, then click **Next**. 3. Assign the following values: - **Product Name:** MyMobileSDKApp - **Team:** A team associated with your Apple Developer account - **Organization Identifier:** A reverse DNS name, such as `com.acme.apps` - **Interface:** **SwiftUI** - **Life Cycle:** **UIKit App Delegate** (This step is not included in Xcode 13 wizards.) - **Language:** **Swift** 4. Accept defaults for **Use Core Data** and **Include Tests**, then click **Next**. 5. Choose a directory for your project, then click **Create**. 6. In Xcode, select a recent iPhone model as the active scheme and click **Run**. The app displays only a blank white screen with the words “Hello, world!” 7. Click **Stop**. # Create Hybrid Apps Once you’ve installed forcehybrid and the Cordova command line, you’re ready to create functioning hybrid apps. ## Set Up Your Tools If you haven’t already set up the required tools, use the following instructions. Or, if you prefer, complete the [Set Up Your Mobile SDK Developer Tools](https://trailhead.salesforce.com/en/projects/mobilesdk_setup_dev_tools) Trailhead project and win Trailhead points for your efforts. Afterwards, return here and pick up at [Create a Hybrid Mobile SDK App](#create-a-hybrid-mobile-sdk-app). **note:** Some of the following steps use the `sudo` keyword. This keyword is required in Mac OS X if you lack read/write permissions. Omit the `sudo` command if you’re sure you don’t need it or if you’re installing on Windows. 1. Make sure that you meet the requirements listed at [Development Prerequisites for iOS and Android](https://developer.salesforce.com/docs/platform/mobile-sdk/guide/dev-prereq.md). Hybrid development requires at least one native environment, which can be either iOS or Android. 2. Open a command prompt or terminal window. 3. Run `cordova -v`. 4. If `cordova -v` reports that the command is not found, install the Cordova command line, version 12.0.0 or later: ```nolang sudo npm install -g cordova ``` 5. Install the forcehybrid npm package: ```nolang sudo npm install -g forcehybrid ``` If you previously installed an earlier version of forcehybrid, be sure to uninstall it before reinstalling forcehybrid. ## Create a Hybrid Mobile SDK App 1. At a command prompt or terminal window, run `forcehybrid create`. - For platform, enter “ios”, “android”, or “ios,android”. - For application type: - Specify `hybrid_local` for a Cordova hybrid app that stores its code on the mobile device. - Specify `hybrid_remote` for a Cordova hybrid app that runs a Visualforce app on the server. - Provide your own app name, package name, and organization strings. - (Hybrid remote apps only) For start page, specify the relative URL of your Apex landing page—for example, `apex/BasicVFPage`. 2. If you’re importing HTML, JavaScript, CSS, or `bootconfig.json` files, put them in your project’s `/www/` directory. **important:** Do not include `cordova.js`, `cordova.force.js`, or any Cordova plug-ins. 3. In your project directory, open the `www/bootconfig.json` file in a UTF-8 compliant text editor and replace the values of the following properties: - `remoteAccessConsumerKey`—Replace the default value with the consumer key from your external client app or connected app - `oauthRedirectURI`—Replace the default value with the callback URL from your external client app or connected app 4. `cd` to your app’s project directory. The force script prints the directory name to the screen when it has finished creating your project. For example: “Your application project is ready in \<_project directory name_>.” 5. For each additional Cordova plug-in you want to add, type: ```nolang cordova plugin add ``` **note:** Go to [https://plugins.cordova.io](http://cordova.apache.org/blog/releases/2013/07/23/cordova-3.html) to search for available plug-ins. 6. (Optional—Mac only) To add a second platform “after the fact”: - To add iOS support, type: ```nolang cordova platform add ios@ ``` - To add Android support, type: ```nolang cordova platform add android@ ``` 7. Type: ```nolang cordova prepare ``` to deploy your web assets to their respective platform-specific directories under the `www/` directory. **important:** During development, always run `cordova prepare` after you’ve changed the contents of the `www/` directory, to deploy your changes to the platform-specific project folders. See “The Command-Line Interface” in the [Cordova 3.5 documentation](http://cordova.apache.org/docs/en/3.5.0/) for more information on the Cordova command line. # Create View Templates Templates let you describe an HTML layout within a container HTML page. To define an inline template in your HTML page, you use a ` ``` 2. In the new ` ``` 3. Add a second script block for a user list template. ```html ``` 4. Define the user list template. Notice that this template contains references to the SmallPhotoUrl, FirstName, LastName, and Title fields from the Salesforce user record. References that use the `<%= varname %>` format are called “free variables” in Ratchet apps. ```nolang ``` 5. Add a third script block for a user details template. ```html ``` 6. Add the template body. Notice that this template contains references to the SmallPhotoUrl, FirstName, LastName, and Title fields from the Salesforce user record. References that use the `<%= varname %>` format in Ratchet apps are called “free variables”. ```html ``` # Creating a Connected App To enable your mobile app to connect to the Salesforce service, you need to create an external client app or connected app. The external client app or connected app includes a consumer key, a prerequisite to all development scenarios in this guide. **note:** Connected apps creation is restricted as of Spring ‘26. You can continue to use existing connected apps during and after Spring ‘26. However, we recommend using [external client apps](https://help.salesforce.com/s/articleView?id=xcloud.external_client_apps.htm) instead. If you must continue creating connected apps, contact Salesforce Support. See [New connected apps can no longer be created in Spring ‘26](https://help.salesforce.com/s/articleView?id=005228017&type=1) for more details. To create an external client app, see [Create an External Client App](https://developer.salesforce.com/docs/platform/mobile-sdk/guide/eca-create.md). # Creating a React Native Project with Forcereact After you’ve successfully installed a native Mobile SDK environment, you can begin creating React Native apps. To create an app, use forcereact in a terminal window or at a Windows command prompt. The forcereact utility gives you two ways to create your app. - Specify the type of application you want, along with basic configuration data. OR - Use an existing Mobile SDK app as a template. You still provide the basic configuration data. In Mobile SDK 9.0, forcereact adds an app type option to support TypeScript: `react_native_typescript`. This type becomes the default for the `forcereact create` command. To instead use standard JavaScript, you specify the `react_native` app type. You can use forcereact in interactive mode with command-line prompts, or in scripted mode with the parameterized command-line version. ## Using Forcereact Interactively To enter application options interactively at a command prompt, type `forcereact create`. The forcereact utility then prompts you for each configuration option. ## Using Forcereact with Command-Line Options If you prefer, you can specify forcereact parameters directly at the command line. To see usage information, type `forcereact` without arguments. The list of available options displays: ```nolang $ forcereact forcereact: Tool for building a React Native mobile application using Salesforce Mobile SDK Usage: # create a React Native mobile application forcereact create --platform=comma-separated list of platforms (ios, android) [--apptype=application type (react_native_typescript or react_native, leave empty for react_native_typescript)] --appname=application name --packagename=app package identifier (e.g. com.mycompany.myapp) --organization=organization name (your company's/organization's name) [--outputdir=output directory (leave empty for current directory)] ``` Using this information, type `forcereact create`, followed by your options and values. For example, to create a React Native app that supports TypeScript: ```nolang $ forcereact create --platform=ios,android --appname=CoolReact --packagename=com.test.my_new_app --organization="Acme Widgets, Inc." --outputdir=CoolReact ``` ## Specifying a Template `forcereact createWithTemplate` is identical to `forcereact create` except that it also asks for a template repo URI. You set this path to point to any repo directory that contains a Mobile SDK app that can be used as a template. Your template app can be any supported Mobile SDK app type—`react_native` or `react_native_typescript`. The force script changes the template’s identifiers and configuration to match the values you provide for the other parameters. Before you use `createWithTemplate`, it's helpful to know which templates are available. To find out, type `forcereact listtemplates`. This command prints a list of templates provided by Mobile SDK. Each listing includes a brief description of the template and its GitHub URI. For example: ```nolang Available templates: 1) Basic React Native application: forcereact createwithtemplate --templaterepouri=ReactNativeTemplate 2) Basic React Native application that uses deferred login forcereact createwithtemplate --templaterepouri=ReactNativeDeferredTemplate 3) Basic React Native application written in TypeScript forcereact createwithtemplate --templaterepouri=ReactNativeTypeScriptTemplate 4) Sample application using MobileSync data framework forcereact createwithtemplate --templaterepouri=MobileSyncExplorerReactNative ``` After you've found a template's URI, you can plug it into the forcereact command line. Here’s command-line usage information for creating a TypeScript project with `forcereact createWithTemplate`: ```nolang forcereact createWithTemplate --platform=Comma separated platforms (ios, android) --templaterepouri=Template repo URI --appname=Application Name --packagename=App Package Identifier (e.g. com.mycompany.myapp) --organization=Organization Name (Your company's/organization's name) [--outputdir=Output Directory (Leave empty for current directory)] ``` For any template in the `SalesforceMobileSDK-Templates` repo, you can drop the path for `templaterepouri`—just the template name will do. For example, consider the following command-line call: ```nolang forcereact createWithTemplate --platform=ios,android --templaterepouri=MobileSyncExplorerReactNative --appname=MyReact -—packagename=com.mycompany.react --organization="Acme Software, Inc." -—outputdir="" ``` This call creates a React Native app in the current directory that supports both iOS and Android. It uses the same source code and resources as the MobileSyncExplorerReactNative sample app. Forcereact changes the app name to “MyReact” throughout the project. ## Build and Run Your App with Android Studio For React Native, Mobile SDK supports both `npm` and `yarn` for package management. When you see both options, the choice is yours. 1. In a Terminal window or at Windows command prompt, change to your project’s root directory. ```nolang cd ``` 2. Run the following command: - `npm start` OR - `yarn start` 3. Open your project in Android Studio. - From the Welcome screen, click **Import Project (Eclipse ADT, Gradle, etc.)**. OR - From the File menu, click **File** | **New** | **Import Project...**. 4. Browse to your `/android/` directory and click **OK**. Android Studio automatically builds your workspace. This process can take several minutes. When the status bar reports “Gradle build successful”, you’re ready to run the project. 5. Click **Run 'app'**, or press `SHIFT+F10`. Android Studio launches your app in the emulator or on your connected Android device. ## Build and Run Your App in Xcode 1. In a Terminal window, change to your project’s root directory. ```nolang cd ``` 2. Type `npm start`, then press Return. 3. In Xcode, open `/ios/.xcworkspace`. 4. Click **Run**. Xcode launches your app in the simulator or on your connected iOS device. ## How the Forcereact Script Generates New Apps - The script downloads templates at runtime from a GitHub repo. For the `forcereact create` command, the script uses the default templates in the [SalesforceMobileSDK-Templates](https://github.com/forcedotcom/SalesforceMobileSDK-Templates) GitHub repo. - The script uses npm to download React Native dependencies. - The script uses git (Android) or CocoaPods (iOS) to download Mobile SDK libraries. # Creating an Android Project with Forcedroid To create an app, use forcedroid in a terminal window or at a Windows command prompt. The forcedroid utility gives you two ways to create your app. - Specify the type of application you want, along with basic configuration data. OR - Use an existing Mobile SDK app as a template. You still provide the basic configuration data. You can use forcedroid in interactive mode with command-line prompts, or in script mode with command-line arguments. To see command usage information, type `forcedroid` without arguments. ## Forcedroid Project Types The `forcedroid create` command requires you to specify one of the following project types: | App Type | Architecture | Language | | ---------------------------------------- | ------------ | -------- | | `native` | Native | Java | | `native_kotlin` (or just press `RETURN`) | Native | Kotlin | To develop a native Android app in Java, specify `native`. ## Using `forcedroid create` Interactively To enter application options interactively at a command prompt, type `forcedroid create`. The forcedroid utility then prompts you for each configuration option. For example: ```bash $ forcedroid create Enter your application type (native, native_kotlin): Enter your application name: testNative Enter the package name for your app (com.mycompany.myapp): com.bestapps.android Enter your organization name (Acme, Inc.): BestApps Enter output directory for your app (leave empty for the current directory): testNative ``` This command creates a native Kotlin Android app named “testNative” in the `testNative\` subdirectory of your current directory. ## Using `forcedroid create` in Script Mode In script mode, you can use forcedroid without interactive prompts. For example, to create a native app written in Java: ```bash $ forcedroid create --apptype="native" --appname="package-test" --packagename="com.acme.mobile_apps" --organization="Acme Widgets, Inc." --outputdir="PackageTest" ``` Or, to create a native app written in Kotlin: ```bash $ forcedroid create --apptype="native_kotlin" --appname="package-test" --packagename="com.acme.mobile_apps" --organization="Acme Widgets, Inc." --outputdir="PackageTest" ``` Each of these calls creates a native app named “package-test” and places it in the `PackageTest/` subdirectory of your current directory. ## Creating an App from a Template The `forcedroid createWithTemplate` command is identical to `forcedroid create` except that it asks for a GitHub repo URI instead of an app type. You set this URI to point to any repo directory that contains a Mobile SDK app that can be used as a template. Your template app can be any supported Mobile SDK app type. The script changes the template’s identifiers and configuration to match the values you provide for the other parameters. Before you use `createWithTemplate`, it's helpful to know which templates are available. To find out, type `forcedroid listtemplates`. This command prints a list of templates provided by Mobile SDK. Each listing includes a brief description of the template and its GitHub URI. For example: ```bash Available templates: 1) Basic Kotlin application forcedroid createwithtemplate --templaterepouri=AndroidNativeKotlinTemplate 1) Basic Java application forcedroid createwithtemplate --templaterepouri=AndroidNativeTemplate 1) Sample Kotlin Identity Provider application forcedroid createwithtemplate --templaterepouri=AndroidIDPTemplate ``` Once you've found a template's URI, you can plug it into the forcedroid command line. Here’s command-line usage information for `forcedroid createWithTemplate`: ```bash Usage: forcedroid createWithTemplate --templaterepouri=