SalesforceLabs / ForcePad

ForcePad: Every Salesforce app, tab, and record, full CRUD, native iOS, slices these carrots, chops these tomatoes
http://appexchange.salesforce.com/listingDetail?listingId=a0N300000055lKrEAI
Other
102 stars 44 forks source link

ForcePad

ForcePad is a free, unofficial, unsupported, open-source native iPad app from Salesforce Labs. It's the easiest way to browse your apps, tabs, and records in any Salesforce environment. Create, edit, clone, and delete standard and custom records. Supports every page layout, every field, every related list, every Group Edition thru Unlimited Edition org. With ForcePad, you're an unstoppable force for the cloud!

ForcePad is on the App Store!      ForcePad is on the Salesforce Appexchange!

by Jonathan Hersh (Email, GitHub, Twitter) with special thanks to Wiebke and Brian in Salesforce UX, Ciara for graphic design and UX, plus Darrell, Eugene, Clarence, Reid, Mike, Simon, Todd, and Kevin.

Author's Note: Account Viewer (which became Salesforce Viewer, which became Salesforce for iPad, which became ForcePad) was my first iOS app, developed over more than a year, so files can show significant variation in quality, conciseness, structure, taste, texture, color, and aroma. The app has also been known to take you out to a nice sushi dinner and then not call you the next day. - JH

In this document:

Release History

ForcePad was originally released as 'Account Viewer' in August 2011. Account Viewer is available on GitHub. In November 2011, Account Viewer was updated and re-released as 'Salesforce Viewer'. In February 2012, I updated it again to Salesforce for iPad. In August 2012 it became ForcePad.

v2.4.1, 2.4.2, 2.4.3 - Released 10/6/2012

v2.4 - Released 9/5/2012

v2.3 - Released 4/5/2012

v2.2.3 - Released 3/13/2012

v2.2.2 - Released 3/6/2012

v2.2.1 - Released 2/20/2012

v2.2 - Released 2/15/2012

ForcePad License

Copyright (c) 2012, salesforce.com, inc. All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Getting Started

  1. Grab the ForcePad source code: git clone https://github.com/ForceDotComLabs/Salesforce-for-iPad.git
  2. ForcePad connects to Salesforce securely with OAuth. If you don't have an OAuth client ID, create a new Remote Access application (Setup -> Develop -> Remote Access). Use the OAuth success endpoint for your callback URL: e.g. https://login.salesforce.com/services/oauth2/success for production. Copy your OAuth Client ID into the OAuthClientID variable in OAuthViewController.h.
  3. (Optional) ForcePad connects to environments that are not otherwise API-enabled, like GE and PE orgs, by using a partner token. If you have a Salesforce partner token, paste it into RootViewController.h under PartnerTokenId.
  4. (Optional) If you have a Google API key, paste it into RecordNewsViewController.h under NEWS_API_KEY.
  5. Build and run, and you should be good to go!
  6. If you're getting build warnings/errors akin to "Multiple build commands for output file...", you'll need to remove the .git directory from your project. See this answer for more detail.

Authentication, APIs, and Security

ForcePad authenticates to Salesforce with OAuth. The app encrypts your OAuth refresh token in the device's keychain. The app never has access to your username or password.

After authentication, ForcePad's API calls are about 30% to the SOAP (Web Services) API and 70% to the REST APIs. REST is the future for mobile and I'm trying to move as much as possible away from SOAP.

SOAP is used for:

REST is used for:

Remote records are never saved locally. Page layouts, sObject describes, and other metadata are cached in-memory and cleared at every logout and refresh.

Some record data (names and addresses) are sent to third-party APIs to provide app functionality, but always over HTTPS. More details below in the External API section.

App preferences (first-run settings, preferences) are stored in NSUserDefaults.

App Architecture

When ForcePad first loads, it evaluates whether it has a stored OAuth refresh token from a previous authentication. If so, it attempts to refresh its session with that refresh token. See appFinishedLaunching in RootViewController.m. If there is no stored refresh token, or if the refresh fails for any reason, the app destroys all session data and shows the OAuth login screen.

The left-side navigation view (in landscape mode, also visible in portrait mode in a popover when you tap the browse button), a.k.a. the Master view, is powered by the RootViewController and SubNavViewController classes. RootViewController handles most of Login/Logout, while SubNavViewController powers record browsing, searching, object lists, and displaying favorite objects.

The right-side view is powered by the DetailViewController. It serves as a container for the rest of the app's content and is responsible for creating, managing, and destroying Flying Windows and the Flying Window stack. It manages dragging operations on Flying Windows.

The interactive, draggable panes that fill the DetailViewController are termed Flying Windows and each is a subclass of the FlyingWindowController class. The FlyingWindowController base class defines some basics about their look and enables them to be dragged about the screen.

Behold ye the Flying Windows:

Modal Windows

AboutAppViewController, SFVEULAAcceptController, and SFVFirstRunController are part of the first-run experience and also power the help pages accessed via the settings window.

ChatterPostController is the main interface for posting an article or URL to chatter.

CloudyLoadingModal probably doesn't do anything important. Look behind you!

OAuthCustomHostCreator, OAuthLoginHostPicker, and OAuthViewController microwave popcorn. Actually, they microwave burritos. Nah, just kidding, they're the brothers who run that corner convenience store.

ObjectLookupController is a lookup box launched when you tap the 'Post To' field in the ChatterPostController. It also handles lookup fields on record editing layouts. It can search via SOQL and SOSL for (almost) any standard or custom object.

PicklistPicker is a popover tableview for selecting from a picklist, multiselect, or combobox. It also handles picking from lists of record types, for use when editing a record.

Miscellaneous Views

FieldPopoverButton is a generic UIButton intended to display the value of an sObject field. All FieldPopoverButtons can be tapped to copy the text value of that field, and depending on the field type, some may have additional actions. For example, a FieldPopoverButton displaying an address will offer to open the address in Google Maps, phone/email fields will offer to call with Facetime or Skype, and lookups to User will display a full-featured user profile with a photo and other details from the User record.

FollowButton is a generic UIBarButtonItem intended to make it easy to create a follow/unfollow toggle between the running user and any other chatter-enabled object (User, Account, etc).

QCContactMenu is a subclass of the super-nifty QuadCurveMenu component intended to make it easy to Email, Skype, Facetime, or open the website for any record. If a page layout has three fields of type Phone, for example, a QCContactMenu, when tapped, will allow you to choose Skype, then place a Skype call to any of those three phone numbers.

Caching

The app has a caching layer to hold metadata in-memory, allowing the app to read metadata from cache instead of re-querying the server. This is mostly contained in SFVAppCache except for page layouts, which are cached in SFVUtil.

Network Operations

Network operations use the block methods in SFVAsync (for SOAP) and the Mobile SDK's SFRestAPI blocks (for REST). SFVUtil contains the app's image loading block method and cache. I added additional REST API blocks under SFRestAPI+SFVAdditions, mostly for the purpose of intercepting object describes and, if cached, immediately returning the cached value.

Security

SFCrypto encrypts and decrypts OAuth session tokens for the device's keychain.

SimpleKeychain is a utility class for reading from and writing to the device's keychain.

External APIs

ForcePad communicates with these APIs over HTTPS.

App Components

ForcePad uses Salesforce components:

And a number of third-party components:

Areas for Improvement

Much is there to do on ForcePad. Some unsolved problems:

Some other things to do: