Git Product home page Git Product logo

swiftlysalesforce's Introduction

Swiftly Salesforce

"The Swift-est way to build native mobile apps that connect to Salesforce."

  

Minimum Requirements

  • iOS 15.0
  • Swift 5.5
  • Xcode 13

Quick Start

Get up and running in less than 5 minutes!

  1. Get a free Salesforce Developer Edition: You can sign up for a free developer environment (also called an "organization" or "org") here. It will never expire as long as you log in at least once every 6 months.

  2. Create a Salesforce Connected App: Create a new Connected App in your developer environment. This screenshot shows an example; you can copy the settings that I've entered. Be sure that "Require Secret for Refresh Token Flow" is not checked.

  3. Add Swiftly Salesforce to your project: Add the Swiftly Salesforce package to your Xcode project (instructions) with the URL https://github.com/mike4aday/SwiftlySalesforce.git.

  4. Create a configuration file: In your Xcode project, create an empty file named Salesforce.json and add the following JSON text, replacing the placeholder text with the actual values for your Connected App's consumer key and callback URL:

{
    "consumerKey" : "<Replace with the consumer key from your Connected App definition>",
    "callbackURL" : "<Replace with the callback URL from your Connected App definition>"
}
  1. Connect to Salesforce: Call Salesforce.connect() and you're ready to go! If you're using SwiftUI, you could call the following from your main application file and store the Salesforce connection in the environment. Swiftly Salesforce will automatically handle all the OAuth flows, authenticating users on their first use of your app and then silently refreshing their access tokens when required.
// MyApp.swift
import SwiftUI
import SwiftlySalesforce

@main
struct MyApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView().environmentObject(try! Salesforce.connect())
        }
    }
}

I expect that you'll find most of the methods you'll need in the file Connection+API.swift but if you require more, you could create your own implementation of DataService and override just the relevant methods. See the source files in the Sources/SwiftlySalesforce/Services folder for examples of DataService implementations that I created.

Here are some examples of using the Connection class' convenience methods:

// ContentView.swift
import SwiftUI
import SwiftlySalesforce

//...
@EnvironmentObject var salesforce: Connection

//...
// Query the current user's accounts
let queryResults: QueryResult<Record> = try await salesforce.myRecords(type: "Account")

// Search for a string in Salesforce records
let searchResults: [Record] = try await salesforce.search(sosl: "FIND {Joe Smith}")

// Get info about the current user
let userInfo: Identity = try await salesforce.identity()

// Retrieve all fields of an Account record
let account: Record = try await salesforce.read(type: "Account", id: "0011Y00003HVMu4QAH")

// Retrieve all fields of an Account record and decode them into your own, custom Decodable instance
let account2: CustomAccount = try await salesforce.read(type: "Account", id: "0011Y00003HVMu4QAH") 

// Insert a new record
let recordID: String = try await salesforce.create(type: "Account", fields: ["Name": "Acme Corp."]

// Update a record
try await salesforce.update(type: "Account", id: "0011Y00003HVMu4QAH", fields: ["BillingCity": "Austin"])

// Get metadata about any Salesforce object, including custom fields, labels, validation rules, etc.
let accountMetadata = try await salesforce.describe("Account")

User Authorization

Swiftly Salesforce will automatically manage all required Salesforce authorization flows. If Swiftly Salesforce already has a valid access token in its secure store, it will include that token in the header of every API request. If the token has expired and Salesforce rejects the request, then Swiftly Salesforce will attempt to refresh the access token without bothering the user to re-enter the username and password. If Swiftly Salesforce doesn't have a valid access token, or is unable to refresh it, then Swiftly Salesforce will direct the user to the Salesforce-hosted login form.

Sample App

Check out MySalesforceAccounts for a complete, working app that uses SwiftUI, Swift concurrency and Swiftly Salesforce to display the user's Salesforce account records. Though it's a relatively-trival app, it illustrates how to configure an app and quickly connect it to Salesforce.

Before you run the sample app, edit Salesforce.json and replace the temporary values for the consumer key and callback URL with those of your own Connected App.

Questions, Suggestions & Bug Reports

swiftlysalesforce's People

Contributors

hmuronaka avatar joaoamaral avatar mike4aday avatar quintonwall avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

swiftlysalesforce's Issues

Can't make it running

Hi,

Disclaimer, I am just learning. I couldn't run the SwiftlySalesforce. I managed to run example, but if I create a new project I just see a white screen of my storyboard. What I did:

  1. create a project
  2. modified app delegate (like in example that working, so that should ok)
  3. modified info.plist (like in example that working, so that should ok)
  4. installed pods (pod install with pod file as specified)
  5. installed carthage (as specified)

couldn't you help me? (attached the project)
test7.zip

How to use SFPushNotificationManager in Swiftly

So I'm able to send a test push to the device from the Salesforce console... However, I believe I'm meant to use the SFPushNotificationManager to get the device token into the User object in salesforce.

Is SFPushNotificationManager not available in SwiftlySalesforce. Will I have to use and auth with the SalesforceMobileSDK-iOS in order to do this?

Limits resource fails as of Spring '17

The JSON response from the REST limits endpoint now includes Connected App-specific limits in the payload, breaking the parser in SwiftlySalesforce. Breaks in all API versions as of Spring '17.

How to cast [Record] to [Account] in query result

I'm using custom model objects with multiple queries, so I declared it like:

first {
    let queries = ["SELECT Name FROM Account", "SELECT Id FROM Contact", "Select Owner.Name FROM Lead"]
    return salesforce.query(soql: queries)
}.then { (results: [QueryResult<Record>]) -> () in
   let accounts = results[0].records
   let contacts = results[1].records
   let leads = results[2].records
}.catch { error in
   
}

My problem is that all the objects are 'Record' and not either 'Account', 'Contact' or 'Lead', I tried a simple let accounts = results[0].records as? [Account] which gives me a warning "Cast from '[Record]' to unrelated type '[Account]' always fails"

Notify caller if failure to save to keychain

In the unlikely event that persisting credentials to the keychain fails, the calling method is not notified. The consequence is that on next use of the application, the user will be asked to log in again, rather than using the refresh token to get a new session ID from Salesforce.

Need a way to notify the caller that keychain persistence failed.

Authorization Not Working

I am completely unsure why authorization is not working for me..

Not working with example app or my integrated app.

I am taken to the callbackURL, but then after that the safari view controller is not dismissed and the app does not retrieve the token.

How many API calls are done per one SOQL statement?

I just started using this today and made it to work. I've been doing some testing today and I think I executed around 100 or so SOQL statements. Tonight, I received an email that the organization has made 11,800+ API calls within the last 24 hours. I wonder if this can be related to with the use of SwiftlySalesforce or maybe something else. Please let me know and any information can help.

bulk insert

All salesforce.insert methods are single record. We've attempted bulk inserts, but get cut off after a small number of records. What's the best way to bulk insert 100-1000 records?

Thanks

Can't access object EventAttendee from Swiftlysalesforce.

soql="SELECT AttendeeId FROM EventAttendee where EventId = '00U5000000QbKtCEAV'"
return salesforce.query(soql: soql)

catch results in:

error: Salesforce response failure. Code: INVALID_TYPE. Message: sObject type 'EventAttendee' is not supported.. Fields: []

Better warning when configuration not set

Redefine Salesforce.configuration with default value and error if that value is used (i.e. if not reset to a valid configuration) with an actionable, more developer-friendly error.

Is it possible to read accessToken

Hi,
is it possible to read the accessToken of my current session? I want to download a user's profile picture and need that token to retrieve the full photo url.
Thanks in advance

OAuth error message confusing to user.

Recently, my testing indicate that the OAuth server (mostly on US weekends) fails with "User authentication required". Attempts to re-authenticate fail as well. From the code below, looks like 401,403 is the reason. Could you please elaborate on the root cause, and if it is (as we believe) a server issue, sharpen the error message to the user?

fileprivate func send<T,U>(urlRequest: URLRequest, jsonDeserializer: @escaping (U) throws -> T) -> Promise {
return Promise {
fulfill, reject in
Alamofire.request(urlRequest)
.validate {
(request, response, data) -> Request.ValidationResult in
switch response.statusCode {
case 401, 403:
return .failure(SalesforceError.userAuthenticationRequired)

JSON V5 (codable) fails on nil LastactivityDate

"dataCorrupted(Swift.DecodingError.Context(codingPath: [SwiftlySalesforce.QueryResult<AccountManager.Account>.CodingKeys.records, Foundation.(_JSONKey in _12768CA107A31EF2DCE034FD75B541C9)(stringValue: "Index 6", intValue: Optional(6)), AccountManager.Account.CodingKeys.LastActivityDate], debugDescription: "Date string does not match format expected by formatter.", underlyingError: nil))"

We used to manage nil dates. How do we work around this? Thx.

Build ERROR with Locksmith 3.0.0 Xcode 8.3.2

Hello, I try adding SwiftlySalesforce to project pod file after opening generated workspace I see new dependencies been added. But build error with many syntax errors on Locksmith 3.0.0 framework looks like use of _ in function types and NSBundles. Seem Xcode like to add _ on functions? Any solutions for this?

Using Xcode 8.3.2 and Swift 3.1
Apple Swift version 3.1 (swiftlang-802.0.53 clang-802.0.42)
Target: x86_64-apple-macosx10.9

organization() does not return organization info

Should the following not work? (a la identity())
first {
salesforce.organization()
}.then {
(org) -> Promise in
if let nameSpacePrefix = org.nameSpacePrefix {
print("using namespaceprefix (nameSpacePrefix)")
}
}

Support for TLS 1.1?

This is more of a question than issue: does SwiftlySalesforce support the switch to TLS 1.1 that Salesforce is pushing through? If so, since what version of SwiftlySalesforce is the case? I'm trying to determine whether I need to rebuild (and perhaps modify) an app that was built on SwiftlySalesforce this summer. Thank you!

Couldn't install using pod.

Hi, I tried to install SwiftlySalesforce 2.0.1 but I coudn't.
I think that the git-tag 2.0.1 does not exist.

Thanks,

Swift 3.0 conversion failing

Hello, I am trying to get this to compile for a test project using XCode 8, Swift 3.0, and iOS 10. The pods are not compiling at the moment?
screen shot 2017-02-21 at 2 33 50 pm

Swift 3.0 support

Supporting Swift 3.0 and latest dependencies (PromiseKit and LockSmith).

Error in Swift 4 host app

App throws ''dyld: Library not loaded" error when host target kept as swift language version 4 and SwiftlySalesforce target kept in Swift 3 (in Xcode 9)

dyld: Library not loaded: @rpath/SwiftlySalesforce.framework/SwiftlySalesforce
Referenced from: /Users/developer/Library/Developer/CoreSimulator/Devices/E8C812E3-D066-42B1-9577-831385897C76/data/Containers/Bundle/Application/6FCB02FF-4668-491B-AD97-7ECAD25B28D1/SwiftlySample.app/SwiftlySample
Reason: no suitable image found. Did find:
/Users/developer/Library/Developer/CoreSimulator/Devices/E8C812E3-D066-42B1-9577-831385897C76/data/Containers/Bundle/Application/6FCB02FF-4668-491B-AD97-7ECAD25B28D1/SwiftlySample.app/Frameworks/SwiftlySalesforce.framework/SwiftlySalesforce: required code signature missing for '/Users/developer/Library/Developer/CoreSimulator/Devices/E8C812E3-D066-42B1-9577-831385897C76/data/Containers/Bundle/Application/6FCB02FF-4668-491B-AD97-7ECAD25B28D1/SwiftlySample.app/Frameworks/SwiftlySalesforce.framework/SwiftlySalesforce'

Even after successful pod install project does not run at all

Hi,

I have created a blank project and successfully able to run pod 'SwiftlySalesforce' to download all the dependencies. All 5 dependencies download correctly and project workspace file created.

I opened workspace and did all setup in "Configure Your App Delegate for Salesforce also provided consumerKey and callback url" as per the instructions given in below link
https://github.com/mike4aday/SwiftlySalesforce

Then i have tried to run the app, app did not get run due to the downloaded dependancies errors which cannot be fixed manually at developer side.

Please see attached screenshots for refrance
screen shot 2017-11-28 at 1 06 48 pm
screen shot 2017-11-28 at 1 09 14 pm
screen shot 2017-11-28 at 1 09 59 pm
screen shot 2017-11-28 at 1 36 45 pm

I have checked with both xcode versions 9.0 and 9.1.
Alamofire errors
Locksmith errors

I don't think we need to fix these errors manually.

Sample is running but through pod setup i am not able to use salesforce, instructions are waist if it can not work as expected.

I am blocked here now. Kindly provide me the solution so that i can attache latest Salesforce to my existing project through pods.

Thanks & Regards,
Nishant Singh

Question: How can I access inner query records?

From a query with an inner query like:

first {
    let soql = "SELECT Id, Name, (SELECT Id, Name FROM Contacts) FROM Account"
    return salesforce.query(soql: soql)
}.then { (result: QueryResult) -> () in
    let accounts = result.records.map { Account(dictionary: $0) }
    self.accounts = accounts
    fulfill(accounts)
}.catch { error in
    reject(error)
}

I'm trying to access the inner records in the 'parser' function like:

init(dictionary: [String:Any]) {
        
    for (key, value) in dictionary {
        switch key.lowercased() {
        case "id":
            self.id = value as? String
        case "name":
            self.name = value as? String
        case "contacts":
            //Not working
            let result = value as? QueryResult
            self.contacts = result?.records.map { Contact(dictionary: $0) }
        default:
            continue
        }
    }
}

But the let result = value as? QueryResult is not working.

Examples of SOQL with subquery and groups

Could you please add examples of both
Subquery: "SELECT Id, Name, (SELECT Id, Name FROM Contacts) FROM Account"
and
Grouped: "SELECT Id, count(name) from account"

showing the most elegant way to parse the JSON results.

Could I use this to download a file from salesforce?

First let me start by saying that this wrapper is incredible! I'm a huge fan!

I'm attempting to connect to Salesforce (custom object) and I would like to download the actual file which is stored in Attachment Body field. When my QueryResult comes back it has the path to my field instead of the base64 encoded string. When I execute my soql at workbench @ developerforce I see the full base64 string. I suppose I could just use AlamoFire and issue a request to download the file, but I love the way that all of the token support is built in for this api.

Any thoughts for the best way to accomplish this using SwiftlySalesforce? Would a .custom request be the right option in this case? Could you provide an example for me for this type of request? It seems like it requires headers to be passed into it...if so should I be grabbing those from the connectedApp instance?

Thanks for all the hard work! Big thumbs up.
Bart

salesforce.describe does not seem to handle multiple objects

Example from README suggest that you can retrieve meta data for multiple objects.
"first {
salesforce.describe(types: ["Account", "Contact", "Task", "CustomObject__c"])"

I can't get multiple objects to work. Here's the func from Salesforce.swift, suggesting that only one object works:

open func describe(type: String) -> Promise {
let builder = {
(authData: AuthData) throws -> URLRequest in
return try Router.describe(type: type, authData: authData, version: self.version).asURLRequest()
}
let deserializer = {
(response: [String: Any]) throws -> ObjectDescription in
return ObjectDescription(json: response)
}
return request(requestBuilder: builder, jsonDeserializer: deserializer)
}

Not able to open another URL of SF after opening login URL on Safari controller

Hi,

I'm using swiftly salesforce to for login to salesforce account from my iPhone app using Swift 3.0. I have followed this SwiftlySalesforce link.

Here swiftly salesforce replaces your rootviewController with SFSafariViewController. Once login is done it will replace safari view controller with your initial rootviewController. I'm able to get all details of user from which I have logged in. Now on my initial view which is my rootview, I want to show chatter page which usually comes after successful login on webview. But I'm getting login page again on webview.

I think this is happening because the login seesion I'm getting from safari View controller is not getting to webview. Or is there any other issue?

If anyone have worked on such requirement, or anyone could help me, please post your answers here. Your help is appritiated.

Thank you,
Ankita

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.