Your SlideShare is downloading. ×
Tulsa Dev Lunch iOS at Work
Tulsa Dev Lunch iOS at Work
Tulsa Dev Lunch iOS at Work
Tulsa Dev Lunch iOS at Work
Tulsa Dev Lunch iOS at Work
Tulsa Dev Lunch iOS at Work
Tulsa Dev Lunch iOS at Work
Tulsa Dev Lunch iOS at Work
Tulsa Dev Lunch iOS at Work
Tulsa Dev Lunch iOS at Work
Tulsa Dev Lunch iOS at Work
Tulsa Dev Lunch iOS at Work
Tulsa Dev Lunch iOS at Work
Tulsa Dev Lunch iOS at Work
Tulsa Dev Lunch iOS at Work
Tulsa Dev Lunch iOS at Work
Tulsa Dev Lunch iOS at Work
Tulsa Dev Lunch iOS at Work
Tulsa Dev Lunch iOS at Work
Tulsa Dev Lunch iOS at Work
Tulsa Dev Lunch iOS at Work
Tulsa Dev Lunch iOS at Work
Tulsa Dev Lunch iOS at Work
Tulsa Dev Lunch iOS at Work
Tulsa Dev Lunch iOS at Work
Tulsa Dev Lunch iOS at Work
Tulsa Dev Lunch iOS at Work
Tulsa Dev Lunch iOS at Work
Tulsa Dev Lunch iOS at Work
Tulsa Dev Lunch iOS at Work
Tulsa Dev Lunch iOS at Work
Tulsa Dev Lunch iOS at Work
Tulsa Dev Lunch iOS at Work
Tulsa Dev Lunch iOS at Work
Tulsa Dev Lunch iOS at Work
Tulsa Dev Lunch iOS at Work
Tulsa Dev Lunch iOS at Work
Tulsa Dev Lunch iOS at Work
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×
Saving this for later? Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime – even offline.
Text the download link to your phone
Standard text messaging rates apply

Tulsa Dev Lunch iOS at Work

218

Published on

This the deck I used for a talk on integrating iOS into back office systems at the February 13, 2013 Tulsa Dev Lunch.

This the deck I used for a talk on integrating iOS into back office systems at the February 13, 2013 Tulsa Dev Lunch.

Published in: Technology
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total Views
218
On Slideshare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
Downloads
2
Comments
0
Likes
0
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide

Transcript

  • 1. iOS at Work: Integrating iOS Apps with Back End Systems Tulsa Dev Lunch February 13, 20 1 3 Mat llowaoydinaire) t Ga a r obile Develo per Extr (Fr eelance MWednesday, February 13, 13
  • 2. h at a bo ut W d? A n dr oiWednesday, February 13, 13
  • 3. Android s ucks. (Espec ially for business.)Wednesday, February 13, 13
  • 4. Most Consistent API Consistent Hcxrdwcxre -- Best Securit.Y 1=eel G-ood Kumb·,cx Pseudo Open Source-nessWednesday, February 13, 13
  • 5. aid, most of what I’m gonna say a bout iOS applies to Android too. That s Meh.Wednesday, February 13, 13
  • 6. Th ink m obile! Th ink n ow!Wednesday, February 13, 13
  • 7. Ch aracteristi cs of Mobile not a keyboard /mouse paradigm small screen unreliable low bandwidth high latency network connection ocessing power a nd local storage limited pr limited battery life hostile work environment untapped resources: camera(s), acceler ometers, GPS, phone, speaker, mic, LED flashWednesday, February 13, 13
  • 8. Wednesday, February 13, 13
  • 9. Mo bile w eb or die.Wednesday, February 13, 13
  • 10. Natrve (iOS, Android, Blackberry, Windows Phone) App Window Flll~dwith a single Awesome Dashboard We.bVIeW widget loaded "App" With your mobile web content. Awesome Dashboard "App"Wednesday, February 13, 13
  • 11. Wednesday, February 13, 13
  • 12. When the web wo n’t do. Performance/Responsiveness/UX. Complex lo cal data store. Ne twork optional. Hardware control. Sophisticated UI. 3D/a ccelerated graphics.Wednesday, February 13, 13
  • 13. re ent erprise mobile How a ap ps diff erent? Complex local data st res. o I ntegration wi th back office systems.Wednesday, February 13, 13
  • 14. ,..__---------~----~~ Mob.1le Inte_gr~t:1on J>os &- J>onts , OV 0 Cove-r -the Yet) I I I I I I Crf ~oLA he>.ve -t:.o) / I I I I I I I I f>ov-ts B$Z> &-443 I I I IWednesday, February 13, 13
  • 15. Protot_yp·,ccxrash EVterpr·,se Arch.atecture "" -+l - .a... ~ • H o (/) (J ;.J <U H ~ LU"" • H ~ LU"" (J • :J >l-... cS <(_ LU-tJ (J <(_ LU-tJ <Sw hZ. -:s ~ (U -:s ~ (U sG.- _g ""~ 4- h "" 4- h "" cu(/)V) r- ""~ r- ""~ r-~ r-~ 3~~ (/) (/) ""Q_. LU LU<!. LU LU<!. _J (/) p!. z~ p!. z~ • . ~h • l- I. D~t~ Stov-e Bus·aness D~t~ Present~ t·aon Access Lo.9·acWednesday, February 13, 13
  • 16. -~ EVtev-pv-·,se Av-ch·,tectuv-e)( .- ...Q 0 ~ D~t~ Stov-e D~t~ AccessWednesday, February 13, 13
  • 17. D~t~ Stov-e Present~ t·aon ) Bus·aness Lo.9·ac; &- D~t~ AccessWednesday, February 13, 13
  • 18. "EVtev-pv-·ase" Av-ch.atectuv-e <;tu·ack·,e Mob·,r,z.cxt·aoV t=·,x .- ...Q 0 ~ D~t~ Stov-e Present~ t·aon ) Bus·aness Lo.9·ac; / oLA VeeO to • &- D~t~ Access bLA.,0 -tn S.Wednesday, February 13, 13
  • 19. Discl aimer : I’m not .NET devel oper, bu tIe xper iment ed a little in co llege.Wednesday, February 13, 13
  • 20. In Vis ual St udio... 1.) Create a Web Project a new Entity Model 2.) Create 3.) Reverse enginee r Entity Model from Database reate a WCF Dat a Service o 4.) C odel Cl ass t Add y our En tity M 5.) ration decla . class cess the S ervice a ac onf igure dat 6.) CWednesday, February 13, 13
  • 21. [JSONPSupportBehavior] public class Service : DataService<YourEnterpriseEntities> { // This method is called only once to initialize service-wide policies. public static void InitializeService(DataServiceConfiguration config) { // config.SetEntitySetAccessRule("*", EntitySetRights.AllRead); config.SetEntitySetAccessRule("Locations", EntitySetRights.AllRead); config.SetEntitySetAccessRule("Customers", EntitySetRights.All); config.SetEntitySetAccessRule("SalesOrders", EntitySetRights.All); config.SetEntitySetAccessRule("Secrets", EntitySetRights.None); //Set a reasonable paging site config.SetEntitySetPageSize("*", 25); config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V2; } }Source:http://www.hanselman.com/blog/CreatingAnODataAPIForStackOverflowIncludingXMLAndJSONIn30Minutes.aspxWednesday, February 13, 13
  • 22. http:LLyourhost.comLservice.svcLCustomers() http:LLyourhost.comLservice.svcLCustomers(34) http:LLyourhost.comLservice.svcLCustomers()? $filter=substringof(itactile,Name) or substringof(Galloway ,ContactLastName)& $format=json http:LLyourhost.comLservice.svcLCustomers(34)? $expand=Sales0rders$format=jsonWednesday, February 13, 13
  • 23. http:LLyourhost.comLservice.svcL?~format=json { "d" • • { "Enti tySets" : [ "Batches", "Drawings", "DrawingTypes", "Elements", "ElernentAnswers", "ElernentAnswerPhotoes", "ElernentGroups", "Elernenticons", "ElernentQuestions", "ElernentRequirernents", "ElernentTypes", "LocationMetaDatas", "LocationMetaDataFields", "Locations", "PickListirnages", "Projects", "StoreAccesses", "sysdiagrarns", "TestTables", "tlkDivisions", "UpdElernents", "UpdElernentAnswers", "UpdElernentAnswerPhotoes", "UpdLocationMetaDatas", "Users" ] } }Wednesday, February 13, 13
  • 24. http://yourhost.com/service.svc/ElementTypes?Sfor.mat=json { "d" : [ { " metadata": { "uri": "http: //yourhost.com/service.svc / ElementTypes(1)", "type": "YourDataModel.ElementType" }, "elementTypeid": 1, "name": "POS 1&2 Camera", "elementGroupid": 1, "lastModified": "/Date(1340728631167)/", "active": true, "elementiconid" : 3 4, "Elements" : { "_deferred": { "uri": "http: //yourhost.com/service.svc / ElementTypes(1) / Elements" } } , "ElementGroup": { "_deferred": { "uri": "http://yourhost.com/service.svc/ElementTypes(1)/ElementGroup" } } , "Elementicon" : { "_deferred": { "uri": "http: //yourhost.com/service.svc / ElementTypes(1) / Elementicon" } }, "ElementRequirements": { "_deferred": { "uri": "http: //yourhost.com/service.svc / ElementTypes(1) / ElementReguirements" } }, "DrawingTypes": { "_deferred": { "uri": "http: //yourhost.com/service.svc / ElementTypes(1) /DrawingTypes " } }, "ElementQuestions": { "_deferred": { "uri": "http: //yourhost.com/service.svc / ElementTypes(1) / ElementOuestions" } } } { " metadata": { "uri": "http: //yourhost.com/service.svc / ElementTypes(2)", "type": "YourDataModel.ElementType" }, "elementTypeid": 2, "name": "POS 3&4 Camera", "elementGroupid": 1, "lastModified": "/Date(1340728631167)/",Wednesday, February 13, 13
  • 25. http://yourhost.com/service.svc/ElementTypes(l)?Sformat=json& Sexpand=ElementGroup { "d" : { " metadata" : { "uri": "http : //yourhost.com/service.svc/ElementTypes(1)", "type" : "QTSecurityModel . ElementType" }, "elementTypei d": 1, "name" : "POS 1&2 Camera", "elementGroupid" : 1 , "lastModif i ed" : "/Date( 1340728631167) /", "active": true, "elementiconi d" : 34, "Elements" : { "_ de f erred" : { "uri": "http : //yourhost.com/service.svc/ElementTypes(1)/Elements" } } , "ElementGroup": { "_metadata": { "uri": "http://yourhost.com/service.svc/ElementGroups(1)", "type": "QTSecurityModel.ElementGroup" }, "elementGroupid": 1, " name": "Cameras", "sortOrder": 1, "lastModified": "/ Date(1340289282327)/", " active": true, "ElementTypes": { "_deferred": { "uri": "http://yourhost.com/service.svc/ElementGroups(1)/ElementTypes" } } } , "Element i con" : { "_ de f erred" : { "uri": "http : //yourhost.com/service.svc/ElementTypes(1)/Element i con" } }, "ElementRequirements" : { "_ de f erred" : { "uri": "http : //yourhost.com/service.svc/ElementTypes(1)/ElementReguirements" } } , "DrawingTypes" : { "_ de f erred" : { "uri": "http : //yourhost.com/service.svc/ElementTypes(1)/DrawingTypes" } }, "ElementQuestions" : { "_ de f erred" : { "uri": "http : //yourhost.com/service.svc/ElementTypes(1)/ElementOu estions" } } } }Wednesday, February 13, 13
  • 26. The M obile Dev POVWednesday, February 13, 13
  • 27. Reading Data+(id) syncRequest: (NSString *) urlString error:(NSError **) error { NSLog(@"syncRequest: %@",urlString); urlString=[SyncHelper addJsonToUri:urlString]; // Adds ?$format=json to URL NSURL *url = [NSURL URLWithString:urlString]; NSError *internalError = nil; NSURLResponse *response=nil; NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; if (HTTP_USER!=nil && [HTTP_USER length]>0 && HTTP_PASSWORD!=nil && [HTTP_PASSWORD length]>0) { NSString *authStr = [NSString stringWithFormat:@"%@:%@",HTTP_USER,HTTP_PASSWORD]; NSData *authData = [authStr dataUsingEncoding:NSASCIIStringEncoding]; NSString *authValue = [NSString stringWithFormat:@"Basic %@", [authData base64EncodingWithLineLength:80]]; [request setValue:authValue forHTTPHeaderField:@"Authorization"]; } NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&internalError]; if (!internalError) { internalError=nil; NSDictionary *interimDict = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers|NSJSONReadingAllowFragmentserror:&internalError]; if (internalError!=nil) { NSLog(@"Error parsing JSON from syncRequest: %@ ",[internalError debugDescription]); if (error!=nil) *error=internalError; return nil; } NSDictionary *errorDict = [interimDict objectForKey:@"error"]; if (errorDict!=nil) { NSDictionary *messageDict = [errorDict objectForKey:@"message"]; NSString *errorMessage = [messageDict objectForKey:@"value"]; if (error!=nil) *error=[NSError errorWithDomain:ERROR_DOMAIN code:4000 localizedDescription:[NSString stringWithFormat:@"Error received fromserver: %@",errorMessage]]; return nil; }Wednesday, February 13, 13
  • 28. id retVal = [interimDict objectForKey:@"d"]; if ([retVal isKindOfClass:[NSDictionary class]] && [((NSDictionary *)retVal) objectForKey:@"results"]!=nil) { return [((NSDictionary *)retVal) objectForKey:@"results"]; } else { return retVal; } } else { NSLog(@"Error: unable to complete web request because - %@",[internalError localizedDescription]); if (error!=nil) *error=internalError; return nil; } NSArray } If result is a list, an NSMutab leDiction ary’s is of ret urned. Otherwise, an NSMutableDictionary is returned.Wednesday, February 13, 13
  • 29. Inserting New Data +(BOOL) insertEntity:(id) entity entityName:(NSString *)entityName error:(NSError **) error { NSString *urlString = [SyncHelper urlStringForEntity:entityName]; // Turns “EntityName” into “http://yourserver/service.svc/EntityName NSURL *url = [NSURL URLWithString:urlString]; NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; [request setHTTPMethod:@"POST"]; [request addValue:@"Application/json" forHTTPHeaderField:@"content-type"]; [request addValue:@"Application/json" forHTTPHeaderField:@"accept"]; [request setValue:@"gzip" forHTTPHeaderField:@"Accept-Encoding"]; if (HTTP_USER!=nil && [HTTP_USER length]>0 && HTTP_PASSWORD!=nil && [HTTP_PASSWORD length]>0) { NSString *authStr = [NSString stringWithFormat:@"%@:%@",HTTP_USER,HTTP_PASSWORD]; NSData *authData = [authStr dataUsingEncoding:NSASCIIStringEncoding]; NSString *authValue = [NSString stringWithFormat:@"Basic %@", [authData base64EncodingWithLineLength:80]]; [request setValue:authValue forHTTPHeaderField:@"Authorization"]; } NSError *internalError = nil; NSData *payload = [NSJSONSerialization dataWithJSONObject:entity options:NSJSONWritingPrettyPrinted error:&internalError]; if (internalError != nil) { if (error!=nil) *error = internalError; return NO; } [request setHTTPBody: payload]; NSHTTPURLResponse *response = nil; internalError = nil; NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&internalError]; if (internalError != nil) { if (error!=nil) *error = internalError; return NO; } NSString *responseStatus = [NSHTTPURLResponse localizedStringForStatusCode:[response statusCode]]; if ([response statusCode]!=201) { if (error!=nil) *error = [NSError errorWithDomain:ERROR_DOMAIN code:100 localizedDescription:[NSString stringWithFormat:@"HTTP ERROR (%i) %@",[response statusCode],responseStatus]]; } return [response statusCode]==201; }Wednesday, February 13, 13
  • 30. +(BOOL) updateEntity:(NSMutableDictionary *)entity forKeys:(NSArray *)keys error:(NSError **) error { NSDictionary *metadata = [entity valueForKey:@"__metadata"]; if (metadata==nil) return NO; NSURL *url = [NSURL URLWithString:[metadata valueForKey:@"uri"]]; NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; [request [request setHTTPMethod:@"POST"]; addValue:@"MERGE" forHTTPHeaderField:@"X-HTTP-Method"]; Updating Data [request addValue:@"Application/json" forHTTPHeaderField:@"content-type"]; [request addValue:@"Application/json" forHTTPHeaderField:@"accept"]; [request setValue:@"gzip" forHTTPHeaderField:@"Accept-Encoding"]; if (HTTP_USER!=nil && [HTTP_USER length]>0 && HTTP_PASSWORD!=nil && [HTTP_PASSWORD length]>0) { NSString *authStr = [NSString stringWithFormat:@"%@:%@",HTTP_USER,HTTP_PASSWORD]; NSData *authData = [authStr dataUsingEncoding:NSASCIIStringEncoding]; NSString *authValue = [NSString stringWithFormat:@"Basic %@", [authData base64EncodingWithLineLength:80]]; [request setValue:authValue forHTTPHeaderField:@"Authorization"]; } NSMutableDictionary *payloadDict = [NSMutableDictionary dictionaryWithCapacity:10]; [payloadDict setValue:metadata forKey:@"__metadata"]; for (NSString *key in keys) { [payloadDict setValue:[entity valueForKey:key] forKey:key]; } NSError *internalError = nil; NSData *payload = [NSJSONSerialization dataWithJSONObject:payloadDict options:NSJSONWritingPrettyPrinted error:&internalError]; if (internalError != nil) { if (error!=nil) *error = internalError; return NO; } [request setHTTPBody: payload]; NSHTTPURLResponse *response = nil; internalError = nil; NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&internalError]; if (internalError != nil) { if (error!=nil) *error = internalError; return NO; } NSString *responseStatus = [NSHTTPURLResponse localizedStringForStatusCode:[response statusCode]]; if ([response statusCode]!=204) { if (error!=nil) *error = [NSError errorWithDomain:ERROR_DOMAIN code:5000 localizedDescription:[NSString stringWithFormat:@"HTTP ERROR (%i) %@",[response statusCode],responseStatus]]; } return [response statusCode]==204; }Wednesday, February 13, 13
  • 31. What to Do With an NSMutableDictionary? 1.) Parse into proper objects 2.) Create a wrapper object that stores NSMutableDictionary internally 3.) Use Objective-C Categories to add field-like methods to NSMutableDictionary But don’t just [object objectForKey: @“propertyName“]Wednesday, February 13, 13
  • 32. // // NSMutableDictionary+Customer.m // Yale Cleaners // // Created by Matt Galloway on 8/31/12. // Copyright (c) 2012 Architactile LLC. All rights reserved. // #import "NSMutableDictionary+Customer.h" @implementation NSMutableDictionary (Customer) #pragma mark - Customer Custom Getters -(NSString *) mobileNumber { ple return [self filteredObjectForKey:@"Mobile_no"]; } am -(NSString *) sendEmail { return [self filteredObjectForKey:@"SendEmail"]; } Ex -(NSString *) sendReceipt { return [self filteredObjectForKey:@"SendReceipt"]; } ry -(NSString *) sendText { return [self filteredObjectForKey:@"SendText"]; } ego -(NSString *) username { return [self filteredObjectForKey:@"User_Name"]; } t -(NSString *) uri { return [self filteredObjectForKey:@"uri"]; Ca } -(NSString *) address { return [self filteredObjectForKey:@"address"]; -(NSString *) area { return [self filteredObjectForKey:@"area"]; } -(NSString *) charge { return [self filteredObjectForKey:@"charge"]; } -(NSString *) city { return [self filteredObjectForKey:@"city"]; } . . .Wednesday, February 13, 13
  • 33. Use HTT PS + Au then tica tion (at a mini mum)Wednesday, February 13, 13
  • 34. Loca l Data Store? M eet SQ Lite & Cor eDataWednesday, February 13, 13
  • 35. ata is one of iOS’s CoreD greate st adv antag es over d for b usiness apps. AndroiWednesday, February 13, 13
  • 36. PrtmaryK _y _--1 _e;_ • Anr butt~ hc: dlypc: Louuonvet.lO.lt.l-, - C Locat o n _----,~ _o _ _ JSOnW~t~Od i fied Annb~o~tcs 1 Auro butes 9 loatoorMet~DJ.tJfield ld jsonlilstY.od I fled OJddrusl ,~e ocatton~ctOJDiltald .lddreu2 pockl stCho ces vo~lu tBool City required v.llu eno~t folde r arne • Rclattons hips VJ.Iuelnt htghCr. mc:Locat.on J S.onuu~od o ticd location~c:tt~Oata < valueText - Rc ta11onsh1ps loutoOflld !ocatton loutlonN u mber .; Pr OJeCt lame • Attll bU IC!S state folderNam e ~urveyCiodT me j sonl.astli~ocM1ed surveyor name: sutleySctleduled-IIM proJectld syn<Corn !)lete Re ~l i O nships draw-ng-ypes elementRe qul rements :~:~::~:d~~ sytI(Complete 2op cotNple-Le I J ~ fc:: Re :lto hlps ons >dtolwings Elemc:ntRc:qu rc:rrc:fll 1 0r.Jwingiy____1 JX D•aw r.g • Attribute~ ·--..-j~----+ locattonletaOata ~ ::__j e eme t~tRequi remc:nu Anro butes e ementRequirementld Attributes dr.w,, ngTypeld 1--------- drolw n!lld fa en~rne project JSOtll...lStMOCifled m.lXAllcw.ed JSO nl...lstMOOif1ed m nRc:qu•rcd name heo tgh Relauonsho ps Re atton~h ps JSOfll.astMod•f1ed , . - - - - + - - - - - - - - - --1-- ,..> drav. n!jType drilWi ngs A::llamc: i---1-~---+----------+--+~c: cmc:ntTypc OementTyoe c:o --: c:mc:ntRcquirc:mcnts c c:mentType5 !---t-~PIOJ ects _ _ _ ___,.J scale wlctth Re ·" •onship~ d t.lWlngTypt 1,..:::::1 l ===------:!-------------lL...--~~~ocatoon := ~ " d ---- E ementCroup • Ann b"tc:s elementGroupld 9 Annblltes c:lememTypeld ,conl tlename eemenu _ 1_ , ~ t.~ ~ cc l1.J JsonLut-1octlc:d Jsonl..utAocif,c:d n;amc: sortOrde r Rel.lt on·"s~"c;===i " h t ps narrc: Rc: o!t onhops drilv.ongTypu Element ess er w h /.,.» elementCroup AUt ib->ttS dra~o, ng(()Q(dX c:lementQ..estlons c:lementRequ lremen ts ~;::·~~;=~:n V ·,t. lm0 t. c:lc:mc:nts elementld ~ clcmentll.umber jsonl..ut-1oditied Eltmc:ntQue stlon ~ Attrobutes c: c:mc:ntQI.esbonld ~~ n.1me f Relat o n Sh pS O s no nelpPnotofoename !-------c:iementAnswc:rs help-tltt nchesMax Code ~nd nches4ln json~tlod • tied E c:mentAnswc:r 0 emc ntA.11s"..: rPhoto pnoto.AI owNOt e~ J Auro butes Aur iba.tes :>hotoM.1xCount OJnswc: rlnt crc;atcdOn ohotoM nCount photoRc:qu rell.otcs p cl(L siC no cc:s quest OfITtxt .lnswerText created On e emen!An~"erld etementAnswerPhotold gpsUto tude gpslottgltude no SQL• gpslatttudc: tludong quest on- fpe gpslong tude jsonLOJstAodoficd required jsonLmVoct o foed .lnMod fied sortOrdc:r IJ.stl-od ned ~otor den~e tc:xtMaxleng th Re ilto ons"lps photoNotts Rc: ilto oqhips e ement : :::~~~;~;:rs "< _-------------------,fmentAn~"-C!rPhotos ; +uWednesday, February 13, 13
  • 37. To Re cap... A ndroid sucks. Mobilize your web assets. he mob ile web first.Con sider t Avoid SQL & SOAP. Use RESTful APIs.Co reData i s way w orth it.Wednesday, February 13, 13
  • 38. Mat llowaoydinaire) t Ga a r o bile Develo per Extr (Fre elance M matt@architactile.c om 918 -808- 3072Wednesday, February 13, 13

×