Cartography and Coupons


Published on

Cartography & Coupons - Introduction to iOS 6 MapKit and Passbook. This was the talk I gave on Friday 1/11 at CodeMash v2.0.1.3.

Example code is located at:

Published in: Technology
  • Be the first to comment

Cartography and Coupons

  1. 1. CARTOGRAPHY &COUPONSIntroduction to iOS 6 MapKit &PassBookEric HankinsonDeveloper / Sys Admin for
  3. 3. MapKit iOS 5.1 And Previous„ The Map Kit framework used the Google Mobile Maps (GMM) service to provide map data.„ Significant updates in iOS 4.0 update to actually make MapKit fairly usable„ In iOS 5.0, the Map Kit framework supports the ability to use heading data to rotate a map based on the user’s current orientation. As you can with the Maps app, you can configure your map view to scroll the map according to the user’s current location.„ For Geocoding, post iOS 4.3, Apple recommends to use the Core Location framework 3
  4. 4. IOS 6.0 CHANGES
  5. 5. MapKit iOS 6.0 Changes„ Maps are now supported in Simulator„ The MapKit framework uses Apple’s Maps app by default.„ Apps now have an easier way to launch the Maps app and display points of interest or directions.„ Apps can now register as a routing app „ Not limited to just driving or walking directions „ Includes bicycle or hiking trail, air routes, and for subway or other public transportation „ App does not even have to be installed on the user’s device „ Maps knows about routing apps in the App Store and can provide the user with the option to purchase those apps and use them for directions 5
  6. 6. MapKit iOS 6.0 Changes Cont.„ Apps that do not provide routing directions themselves can also take advantage of both Maps and routing apps.„ Apps can use new interfaces to ask the Maps app to display specific locations or to display routing directions between two locations.„ Apple updated the Location Awareness Programming Guide„ Developers should review their code for calls to renderInContext on the layer backing an MKMapView; failure to do so can cause their apps to crash. If these calls are made off the main thread, they should be eliminated or moved to the main thread. 6
  7. 7. MapKit iOS 6.0 SDK Changes„ Not a whole lot! API compatibility with the MapKit from iOS 5 is maintained.„ Let’s get into specifics! 7
  8. 8. Core Location App Requirements„ Make sure to include the UIRequiredDeviceCapabilities key in the app’s Info.plist file if your app cannot function without Core Location services. „ Include the location-­‐services string „ If you need the accuracy offered by GPS, then include the gps string „ If you need the heading, then include the magnetometer string 8
  9. 9. Verify That Location Services Are Enabled„ Make a call to [CLLocationManager  locationServicesEnabled] to determine if Location Services is enabled for your app 9
  10. 10. Launching Maps app With A Location„ Use openMapsWithItems:  launchOptions: class method of MKMapItem.„ Or, alternatively you can use openInMapsWithLaunchOptions: instance method of MKMapItem 10
  11. 11. Launching Maps app With A Location„ Use openMapsWithItems:  launchOptions: class method of MKMapItem.„ Or, alternatively you can use openInMapsWithLaunchOptions: instance method of MKMapItem-­‐  (void)displayRegionCenteredOnMapItem:  (MKMapItem*)from  {        CLLocation*  fromLocation  =  from.placemark.location;        //  Create  a  region  centered  on  the  starting  point  with  a  10km  span        MKCoordinateRegion  region  =        MKCoordinateRegionMakeWithDistance(fromLocation.coordinate,  10000,  10000);        //  Open  the  item  in  Maps,  specifying  the  map  region  to  display.        [MKMapItem  openMapsWithItems:[NSArray  arrayWithObject:from]              launchOptions:[NSDictionary  dictionaryWithObjectsAndKeys:                                            [NSValue],                                            MKLaunchOptionsMapCenterKey,                                            [NSValue  valueWithMKCoordinateSpan:region.span],                                            MKLaunchOptionsMapSpanKey,  nil]];} 10
  12. 12. CoreLocation Manager Events Reporting „ iOS 5 „ -­‐  (void)locationManager:(CLLocationManager  *)manager                        didUpdateToLocation:(CLLocation  *)newLocation                                      fromLocation:(CLLocation  *)oldLocation„ iOS 6 „ -­‐  (void)locationManager:(CLLocationManager  *)manager                didUpdateLocations:(NSArray  *)locations 11
  13. 13. Registering As A Routing App„ Include the MKDirectionsApplicationSupportedModes key and a document type for handling directions requests in your app’s Info.plist file.„ Declare a geographic coverage GeoJSON file„ Process direction request URLs when they are sent to your app. 12
  14. 14. Configure Xcode Target„ Enable routing requests and specify the types of directions your app is capable of providing. 13
  15. 15. Configure Xcode Target Cont.„ Configure a special document type to handle incoming routing requests. 14
  16. 16. Create a GeoJSON File„ Spec is at{"type":"FeatureCollection","features":[{"type":"Feature","id":"USA-­‐OH","properties":{"fips":"39","name":"Ohio"},"geometry":{"type":"Polygon","coordinates":[[[-­‐80.518598,41.978802],[-­‐80.518598,40.636951],[-­‐80.666475,40.582182],[-­‐80.595275,40.472643],[-­‐80.600752,40.319289],[-­‐80.737675,40.078303],[-­‐80.830783,39.711348],[-­‐81.219646,39.388209],[-­‐81.345616,39.344393],[-­‐81.455155,39.410117],[-­‐81.57017,39.267716],[-­‐81.685186,39.273193],[-­‐81.811156,39.0815],[-­‐81.783771,38.966484],[-­‐81.887833,38.873376],[-­‐82.03571,39.026731],[-­‐82.221926,38.785745],[-­‐82.172634,38.632391],[-­‐82.293127,38.577622],[-­‐82.331465,38.446175],[-­‐82.594358,38.424267],[-­‐82.731282,38.561191],[-­‐82.846298,38.588575],[-­‐82.890113,38.758361],[-­‐83.032514,38.725499],[-­‐83.142052,38.626914],[-­‐83.519961,38.703591],[-­‐83.678792,38.632391],[-­‐83.903347,38.769315],[-­‐84.215533,38.807653],[-­‐84.231963,38.895284],[-­‐84.43461,39.103408],[-­‐84.817996,39.103408],[-­‐84.801565,40.500028],[-­‐84.807042,41.694001],[-­‐83.454238,41.732339],[-­‐83.065375,41.595416],[-­‐82.933929,41.513262],[-­‐82.835344,41.589939],[-­‐82.616266,41.431108],[-­‐82.479343,41.381815],[-­‐82.013803,41.513262],[-­‐81.739956,41.485877],[-­‐81.444201,41.672093],[-­‐81.011523,41.852832],[-­‐80.518598,41.978802],[-­‐80.518598,41.978802]]]}}]} 15
  17. 17. Handling Direction Requests„ Handle requests in your app’s delegate-­‐  (BOOL)application:(UIApplication  *)application                        openURL:(NSURL  *)url    sourceApplication:(NSString  *)sourceApplication                  annotation:(id)annotation  {        if  ([MKDirectionsRequest  isDirectionsRequestURL:url])  {                MKDirectionsRequest*  directionsInfo  =  [[MKDirectionsRequest  alloc]                                                                                              initWithContentsOfURL:url];                //  TO  DO:  Plot  and  display  the  route  using  the                //  source  and  destination  properties  of  directionsInfo.                return  YES;        }        else  {                //  Handle  other  URL  types...        }        return  NO;} 16
  18. 18. PASSBOOK
  19. 19. Sections of a Pass„ Top header„ Main content area„ Additional info„ Barcode 18
  20. 20. Pass Types„ Coupon„ Boarding Pass„ Store Card„ Event Ticket„ Generic/Custom 19
  21. 21. What Comprises a .pkpass file„ Actually a zip file comprised of „ pass.json „ manifest.json „ signature „ background.png „ background@2x.png „ logo.png „ logo@2x.png „ icon.png „ icon@2x.png „ strip.png and strip@2x.png 20
  22. 22. Minimalist pass.json Example{ "formatVersion" : 1, "passTypeIdentifier" : "", "serialNumber" : "001", "teamIdentifier" : "<YOUR TEAM IDENTIFIER>", "organizationName" : "LeanDog, Inc.", "description" : "Coupon for 1 Free Kiss from Iggy"} 21
  23. 23. Generate The Pass Certificate„ Facilitated by the iOS Provisioning Portal„ Create a new Pass Type ID„ Configure the new ID„ Configure the Pass Certificate„ Import the new Certificate for signing the Pass later 22
  24. 24. Add some styling to pass.json{ "formatVersion" : 1, "passTypeIdentifier" : "", "serialNumber" : "001", "teamIdentifier" : "<YOUR TEAM IDENTIFIER>", "organizationName" : "LeanDog, Inc.", "description" : "Coupon for 1 Free Kiss from Iggy", "logoText" : "LeanDog, Inc.", "foregroundColor" : "rgb(255, 255, 255)", "backgroundColor" : "rgb(90, 129, 46)", "labelColor" : "rgb(255, 255, 255)"} 23
  25. 25. Add a barcode to pass.json{ "formatVersion" : 1, "passTypeIdentifier" : "", "serialNumber" : "001", "teamIdentifier" : "<YOUR TEAM IDENTIFIER>", "organizationName" : "LeanDog, Inc.", "description" : "Coupon for 1 Free Kiss from Iggy", "logoText" : "LeanDog, Inc.", "foregroundColor" : "rgb(255, 255, 255)", "backgroundColor" : "rgb(90, 129, 46)", "labelColor" : "rgb(255, 255, 255)", "barcode" : { "message" : "All you need is love", "format" : "PKBarcodeFormatPDF417", "messageEncoding" : "iso-8859-1" }} 24
  26. 26. Add coupon to pass.json{ "formatVersion" : 1, "passTypeIdentifier" : "", "serialNumber" : "001", "teamIdentifier" : "<YOUR TEAM IDENTIFIER>", "organizationName" : "LeanDog, Inc.", "description" : "Coupon for 1 Free Kiss from Iggy", "logoText" : "LeanDog, Inc.", "foregroundColor" : "rgb(255, 255, 255)", "backgroundColor" : "rgb(90, 129, 46)", "labelColor" : "rgb(255, 255, 255)", "barcode" : { "message" : "All you need is love", "format" : "PKBarcodeFormatPDF417", "messageEncoding" : "iso-8859-1" }, "coupon" : { "primaryFields" : [ { "key" : "offer", "label" : "Free Dog Kisses for you!", "value" : "Hooray!" } ] }} 25
  27. 27. Create your Artwork for the Pass„ All images must be saved as PNG24, not PNG8!„ icon.png - 29x29„ icon@2x.png - 58x58„ logo.png - 50x50„ logo@2x.png - 100x100„ strip.png - 320x122„ strip@2x.png - 640x244 26
  28. 28. Let’s Create the manifest.json !„ Contains the SHA1 checksum of all files within the .pkpass„ find  .  -­‐type  f  (  -­‐name  "*.png"  -­‐o  -­‐name  "*.json"  )  -­‐exec   openssl  sha1  {}  ;{ "strip.png":"307dd1dbd85800905e449d28b65eb440df4a930f", "strip@2x.png":"096fa1d23c87cf5a3aae7eb9aacc26d554578941", "icon.png":"6edc9e474a3a487b4ec1bb6dd1cd299d6a96ca13", "icon@2x.png":"438d85e9fda4bb0459e3888c38385e53bd603130", "logo.png":"fb95beb3527fc991f5a3c66b653965804fa73fde", "logo@2x.png":"41723d305913e6741f837b911b4dbd60a817941b", "pass.json":"09ec46e7a9aeb226047d1ea5f678a417d9419998"} 27
  29. 29. Generate The Pass Certificate„ Export just the Pass Type certificate, not the Private Key„ Create passcertificate.pem „ openssl  pkcs12  -­‐in  Certificates.p12  -­‐clcerts  -­‐nokeys  -­‐out   passcertificate.pem  -­‐passin  pass:„ Create passkey.pem „ openssl  pkcs12  -­‐in  Certificates.p12  -­‐nocerts  -­‐out  passkey.pem   -­‐passin  pass:  -­‐passout  pass:12345„ Make sure you have the WWDR Intermediate Certificate & export it as Privacy Enhanced Mail (.pem) format 28
  30. 30. Finally!„ Sign the manifest.json file which generates our signature file „ openssl  smime  -­‐binary  -­‐sign  -­‐certfile  WWDR.pem  -­‐signer   passcertificate.pem  -­‐inkey  passkey.pem  -­‐in  manifest.json  -­‐out   signature  -­‐outform  DER  -­‐passin  pass:12345„ Package everything up into the .pkpass file „ zip  -­‐r  freedogkissescoupon.pkpass  manifest.json  pass.json   signature  logo.png  logo@2x.png  icon.png  icon@2x.png  strip.png   strip@2x.png„ Email yourself with the freedogkissescoupon.pkpass file attached & view it on your iOS 6 device. Or, launch in Mountain Lion.„ View & Celebrate! 29
  31. 31. The Finished Product 30
  32. 32. Whats next?„ Additional Info can be added to both the front & back of the Coupon„ Create a custom app that provides REST-style web services to communicate with Passbook, with endpoints to get the latest version of a pass, register / unregister devices to receive push notifications for a pass, and query for passes registered for a device. „„ Experiment with the other Pass types! 31
  33. 33. 32
  35. 35. Google Maps for iOS SDK„ Need to get an API key from Google „„ Very similar to the Google Maps JavaScript API v3 34
  36. 36. Using the Google Maps iOS SDK#import  "YourAppDelegate.h"#import  <GoogleMaps/GoogleMaps.h>@implementation  YourAppDelegate-­‐  (BOOL)application:(UIApplication  *)application  didFinishLaunchingWithOptions:(NSDictionary  *)launchOptions{        [GMSServices  provideAPIKey:@"YOUR_API_KEY"];        return  YES;}@end 35
  37. 37. Using the Google Maps iOS SDK Cont.#import  "YourViewController.h"#import  <GoogleMaps/GoogleMaps.h>@implementation  YourViewController  {    GMSMapView  *mapView_;}//  You  dont  need  to  modify  the  default  initWithNibName:bundle:  method.-­‐  (void)loadView  {    GMSCamera  camera  =  GMSCameraMake(-­‐33.8683,  151.2086,  6);    mapView_  =  [GMSMapView  mapWithFrame:CGRectZero  camera:camera];    mapView_.myLocationEnabled  =  YES;    self.view  =  mapView_;    GMSMarkerOptions  *options  =  [[GMSMarkerOptions  alloc]  init];    options.position  =  CLLocationCoordinate2DMake(-­‐33.8683,  151.2086);    options.title  =  @"Sydney";    options.snippet  =  @"Australia";    [mapView_  addMarkerWithOptions:options];} 36
  38. 38. Using the Google Maps iOS SDK Cont.-­‐  (void)viewWillAppear:(BOOL)animated  {    [super  viewWillAppear:animated];    [mapView_  startRendering];}-­‐  (void)viewWillDisappear:(BOOL)animated  {    [mapView_  stopRendering];    [super  viewWillDisappear:animated];} 37
  39. 39. More Info„„ Apple’s Location Awareness Programming Guide„„ Apple’s PassKit Programming Guide„„
  40. 40. THAT’S A WRAP! Eric Hankinson @kumichou
  41. 41. COME FLOAT WITH US!Located on a 10,000 square foot boat on theCleveland waterfront, our team exemplifies how Agilevalues & principles are practiced. Come float, deliver,and learn with us, or leverage our expertise to help @leandog