Not everyone plays games; fewer games really take off. But we all use email, we all have systems that we login to just for work. These Enterprise systems are part of a large and ever-growing category of spending for IT Managers. But Enterprise systems ... stink. RubyMotion developers are in a unique position to integrate with these Enterprise Software systems while providing beautiful, functional and elegant interfaces. Join in as we learn why we should be writing Enterprise connected apps, and walk through an example of connecting to Salesforce using their iOS SDK.
2. Who the heck is this guy?
Kevin Poorman,Architect at West Monroe Partners
@codefriar -- Hey, I just met you,And this is crazy, But here's my twitter, So follow me, maybe!
Boring corporate bio here.
-- West Monroe Partners.
#MyBabyDaughterTessa!, #Homebrew(beer), #Ruby,
#AngularJS, #Iot, #Salesforce, #!Java, #!Eclipse,
#FriendsDontLetFriendsUseEclipse
#!boringCorporateness
3. Agenda
1. Why Enterprise software?
2. Challenges - We'll need a Young priest and an Old
priest
3. Tools - We can do it!
4. A Salesforce Example
7. Challenges
Lies, Damn Lies, and SDK's
1. Rest Apis Rest "ish" Apis, Soap Apis and SDKs
2. Authentication - Oauth or else
3. Data Integrity and Security
8. Tools
Time for the how
1. Cocoapods
— ZKsForce
2. Gems
— AFMotion
3. Rakefile!
9. An example with Enterprise CRM Software vendor Salesforce.
Resetting passwords like a Boss.
Talk is cheap, Show me the Code.
— Linus Torvald
10. Enter the Rakefile: Frameworks
### Application Frameworks
# You can *add* to this as neccessary but this is the minimum required
# for Salesforce iOS SDK Use.
app.frameworks += %w(CFNetwork CoreData MobileCoreServices SystemConfiguration Security)
app.frameworks += %w(MessageUI QuartzCore OpenGLES CoreGraphics sqlite3)
— How do you know which ones you need?
(lucky) ? Docs : Build Errors
11. Enter the Rakefile: Libraries
### Additional libraries needed for Salesforce iOS SDK
# You can generally add just about any dylib or static .a lib this way
# These are system dylibs
app.libs << "/usr/lib/libxml2.2.dylib"
app.libs << "/usr/lib/libsqlite3.0.dylib"
app.libs << "/usr/lib/libz.dylib"
# These are provided by Salesforces' iOS SDK.
app.libs << "vendor/openssl/libcrypto.a"
app.libs << "vendor/openssl/libssl.a"
# app.libs << "vendor/RestKit/libRestKit.a"
# app.libs << "vendor/SalesforceCommonUtils/libSalesforceCommonUtils.a"
# app.libs << "vendor/SalesforceNativeSDK/libSalesforceNativeSDK.a"
# app.libs << "vendor/SalesforceOAuth/libSalesforceOAuth.a"
app.libs << "vendor/sqlcipher/libsqlcipher.a"
# app.libs << "vendor/SalesforceSDKCore/libSalesforceSDKCore.a"
app.libs << "vendor/sqlcipher/libsqlcipher.a"
12. Enter the Rakefile: Vendor'd Projects
# RestKit
app.vendor_project "vendor/RestKit",
:static,
:headers_dir => "RestKit"
# Salesforce Common Utils
app.vendor_project "vendor/SalesforceCommonUtils",
:static,
:headers_dir => "Headers/SalesforceCommonUtils"
13. Enter the RakeFile: When good vendors go bad
# Salesforce Native SDK
app.vendor_project "vendor/SalesforceNativeSDK",
:static,
:headers_dir => "include/SalesforceNativeSDK"
Warning, a wall of boring, soulless, corporate code is
coming.
14. class AppDelegate
attr_accessor :window, :initialLoginSuccessBlock, :initialLoginFailureBlock
# def OAuthLoginDomain()
# # You can manually override and force your app to use
# # a sandbox by changing this to test.salesforce.com
# "login.salesforce.com"
# end
def RemoteAccessConsumerKey()
# Specify your connected app's consumer key here
"3MVG9A2kN3Bn17hsUZHiKXv6UUn36wtG7rPTlcsyH8K4jIUB2O2CU4dHNILQ_6lD_l9uDom7TjTSNEfRUE6PU"
end
def OAuthRedirectURI()
# This must match the redirect url specified in your
# connected app settings. This is a fake url scheme
# but for a mobile app, so long as it matches you're good.
"testsfdc:///mobilesdk/detect/oauth/done"
end
def dealloc()
NSNotificationCenter.defaultCenter.removeObserver(self, name:"kSFUserLogoutNotification", object:SFAuthenticationManager.sharedManager)
NSNotificationCenter.defaultCenter.removeObserver(self, name:"kSFLoginHostChangedNotification", object:SFAuthenticationManager.sharedManager)
end
def application(application, didFinishLaunchingWithOptions:launchOptions)
if self
SFLogger.setLogLevel(SFLogLevelDebug)
SFAccountManager.setClientId(RemoteAccessConsumerKey())
SFAccountManager.setRedirectUri(OAuthRedirectURI())
SFAccountManager.setScopes(NSSet.setWithObjects("api", nil))
NSNotificationCenter.defaultCenter.addObserver(self, selector: :logoutInitiated, name: "kSFUserLogoutNotification", object:SFAuthenticationManager.sharedManager)
NSNotificationCenter.defaultCenter.addObserver(self, selector: :loginHostChanged, name: "kSFLoginHostChangedNotification", object:SFAuthenticationManager.sharedManager)
@weakSelf = WeakRef.new(self)
self.initialLoginSuccessBlock = lambda { |info|
@weakSelf.setupRootViewController
}
self.initialLoginFailureBlock = lambda { |info,error|
SFAuthenticationManager.sharedManager.logout
}
end
self.window = UIWindow.alloc.initWithFrame(UIScreen.mainScreen.bounds)
self.initializeAppViewState
SFAuthenticationManager.sharedManager.loginWithCompletion(self.initialLoginSuccessBlock, failure:self.initialLoginFailureBlock)
true
end
def initializeAppViewState()
@window.rootViewController = InitialViewController.alloc.initWithNibName(nil, bundle:nil)
@window.makeKeyAndVisible
end
def setupRootViewController()
navVC = UINavigationController.alloc.initWithRootViewController(HomeScreen.new)
@window.rootViewController = navVC
end
def logoutInitiated(notification)
self.log.SFLogLevelDebug(msg:"Logout Notification Recieved. Resetting App")
self.initializeAppViewState
SFAuthenticationManager.sharedManager.loginWithCompletion(self.initialLoginSuccessBlock, failure:self.initialLoginFailureBlock)
end
def loginHostChanged(notification)
self.log.SFLogLevelDebug(msg:"Login Host Changed Notification Recieved. Resetting App")
self.initializeAppViewState
SFAuthenticationManager.sharedManager.loginWithCompletion(self.initialLoginSuccessBlock, failure:self.initialLoginFailureBlock)
end
end
15. And now for the actually useful bit in all that
def setupRootViewController()
# Yeah, if you could just replace the root view controller with a ProMotion
# Screen, that'd be great.
navVC = UINavigationController.alloc.initWithRootViewController(HomeScreen.new)
@window.rootViewController = navVC
end
16. Using the SDK Functions
def query_sf_for_users
results = SFRestAPI.sharedInstance.performSOQLQuery(
# Salesforce has a fun variant on Sql called
# "SOQL" or Salesforce Object Query Language.
# First Argument is the Query we want to run.
"SELECT id, Name, LastName FROM user",
failBlock: lambda {|e| ap e },
# Method is a fun Method that invokes the named
# method as a lambda.
completeBlock: method(:sort_results)
)
end
17. Using the SDK functions
def reset_password args
UIAlertView.alert("Reset Users Password?",
buttons: ["Cancel", "OK"],
message: "Salesforce will reset their password!") { |button|
if button == "OK"
results = SFRestAPI.sharedInstance.requestPasswordResetForUser(
@id, # id of user to invoke password reset.
failBlock: lambda {|e| ap e },
completeBlock: method(:password_reset_complete)
)
end
}
end
def password_reset_complete response
if(Twitter.accounts.size > 0)
UIAlertView.alert("Password Reset!",
buttons: ["OK", "Tweet"]) { |button|
tweet if button == "Tweet"
}
end
end
19. Q & A
Where we A some Q's
Comments? Snide Remarks?
20. Thank You!
Everything should be as simple as possible, but no
simpler.
-- A. Einstein
Ps: Investigative reporters have discovered that RM 3.5,
will include a third new Ruby Compiler -- for Windows
and Windows Phone 8.1, this will, of course, be the only
redeeming feature of Windows*.