I launched an iphone app (Discounts For Me). The app downloads data from a server. I share some of the lessons learned while building the app and building the server back end in ruby on rails
http://discountsforme.net/
4. App: DiscountsForMe Shows member benefits Based on location V1.0 in app store Memberships: Public radio (KQED) Bank of America card AAA, AARP More…
5.
6. Architecture Server (DiscountsForMe.net) serves data Server is Rails app Iphone app talks to the server <Insert usual SERVER ---- INTERNET CLOUD ---- IPHONEpicture here>
8. Connectivity : Simple Start App makes three server calls ping() get_memberships() get_discounts(my_location, my_memberships) Simulator Iphone over Wi-fi Iphone over 3G LAG-TIME is a problem
9. Connectivity : Minimize Lag Time Noticeable lag time over 3G/Edge Reducing lag time Condense network calls (especially if the user is waiting for data) Download in background So Get_memberships() Get_discounts(my_location, my_memberships) get_memberships_and_discounts(loc, mymems)
10. Iphone Connectivity BIG LESSON 1 : Test on IPHONE (not just simulator) Test with WiFi OFF! (3G can be slow to connect, EDGE even worse) You may need to reorganize the logic to improve response time (I had to) LESSON 2 Test in AirPlane Mode (all RADIOS off)(a frequent reason network apps are rejected )
11. Connectivity Test Quick Ping Which is faster? httpS://www.DiscountsForMe.net/ping http://www.google.com SSL always takes longer to establish connection Use faster sites Another snippet from Erica Sadun’s book(to be verified)
12. Talking to Server : Format Two choices : XML, JSON JSON smaller size than XML (50% less) Json : use TouchJSON library http://code.google.com/p/touchcode/wiki/TouchJSON XML : NSXML(sdk) / TouchXML / KissXMLhttp://www.71squared.co.uk/2009/05/processing-xml-on-the-iphone/
13. Agenda Connectivity Data format Secure Data transfer UDIDs, Keys, analytics Controlling app from server
14. Secure Data Transfer Plain HTTP is fine most of the time If you want to secure data Symmetric key encryption (shared ‘seckr3t’ key on Iphone app and server) Public-private key encryption (e.g. SSH) : private key on server, public key on iphone httpS
15. Secure data transfer : httpS SSL is ‘good enough’ for most of us Get a proper SSL certificate ($30). Self-signed certs don’t work by default Beware connection time is a little longer for httpS Verify your ssl certificate is installed properlyhttp://www.digicert.com/help/
18. Talking to Server : Local Server #ifdef DEBUG// dev #define MEMBER_SERVER @”http://localhost:3000” #else// production #define MEMBER_SERVER @”https://discountsforme.net” #endif - And define ‘DEBUG’ in build configurations
21. Use named methods (getDiscounts Vs connectToURL)@interface ServerConnection : NSObject { } + (BOOL) testConnectivity; + (BOOL) isConnected; + (NSArray *) getMemberships; + (NSArray *) getDiscounts:(NSDictionary *) params; @end
22. Agenda Connectivity Data format Secure Data transfer UDIDs, Keys, multiple versions, analytics Controlling app from server
23. What do I send to the server? get_memberships() No parameters?... Think about including UDID (device id) And a Key (compiled within the app) http://discountsforme.net/iphone/get_memberships http://discountsforme.net/iphone/get_memberships?udid=xxxx&key=yyyy
24. Server Side : Unique Device ID Each mobile device has a uniq ID, etched in hardware (just like MAC address) Your app can send UDID with each request Of course : encrypt it or via SSL Very useful for metrics on app usage How many unique devices have the app Access patterns (repeat uses) Easy account creation (no signup)
25. Server side : access keys Start using ‘access keys’ from day-1 Sample key = “iphone_v1.0_xklajdfoi2” (human readable + hard to guess) Each request to server must have a valid key Easy to control client access Prevent scraping, DOS ..etc Monitoring (what versions are being used) Support multiple versions, easy upgrade
26. Supporting multiple versions May be supporting 2-3 client versions at a time (users don’t always run the latest) Keep old ‘API’ around, build-out new API if (is_v2_or_later(key)) { do something } else {do some thing else} This can get convoluted (see next page…)
28. Supporting Multiple Clients… Have different controllers handle different client versions#define SERVER @”https://foo.com/iphone1”#define SERVER @”https://foo.com/iphone2” Make sure to avoid code duplication Plan-B : End-of-life If ( ! is_supported_version(key)){send_msg(“please upgrade”);}
29. Server side : keeping it secure Make sure ‘secret stuff’ doesn’t get logged in log-files In Rails : class Mobile::MobileController < ApplicationControllerfilter_parameter_logging [:key, :uid] end Output: Processing IphoneController#get_memberships_and_discounts (for 166.137.132.167 at 2009-07-02 16:07:41) [POST] Session ID: 126e5a73742f92f85c1158ea63fd960a Parameters: {"loc"=>"39.282440,-76.765693", "action"=>"get_memberships_and_discounts", "uid"=>”[FILTERED]", "controller"=>"mobile/iphone", "dist"=>"25", "mems"=>"", "key"=>"[FILTERED]"}
30. Server side : Metrics : Logs Log every thing to database, don’t rely on logfiles This gives you pretty good metrics on your app usage On Rails, use around_filteraround_filter :log_access, :only => [:get_discounts, :get_memberships] Thirdparty metrics : FLURRY, PinchMedia…
31. Server side : logging in Rails def log_access start_time = Time.now yield end_time = Time.now elapsed = ((end_time - start_time)*1000.0).to_int begin # b/c we don’t want to error during logging alog = MemberAccessLog.new alog.client_type_id = client_type_id alog.session = session.session_id …. alog.save! rescue end End
32. Logging & Scalability If all your requests are READ-ONLY (from db) it is very easy to scale Load balancer can route requests to any server Database can be replicated easily Write-bound apps are little tricky to scale
33. Agenda Connectivity Data format Secure Data transfer UDIDs, Keys, analytics Controlling app from server
35. Control … Apps changes are not easy to ‘get out’ Approval process takes time Users may not upgrade to latest version Server changes are under your control and easy to deploy So build in control-switches in the app, that can be directed from server
36. Control… One example: Choosing if you are going to show ads? show_ads : {none | admob | tapjoy}
37. Hosting Shared hosting is fine, but others might swamp your DB, CPU ..etc If you can, get a VPS (Virtual Private Server) Plans start from $20 / month (SliceHost, Hosting-Rails ..etc) You have full ROOT access to the server (install packages, run CRON jobs ..etc) EC2 is great (for testing, scaling)