What's new in iOS 7
-
Upload
barcelonaio -
Category
Technology
-
view
119 -
download
0
description
Transcript of What's new in iOS 7
What’s new in iOS 7?Highlights of 1500 new APIs
Jordi Gimenez (@gimix3) & Hermes Pique (@hpique) NSBarcelona
As measured by the App Store during a 7-day period ending February 23, 2014.
82% of devices are using iOS 7.
Agenda
• NSTextStorage • UIViewController transitions • iCloud & Core Data • App Store Receipt • Speech Synthesis • JavaScript Evaluation • New Networking Possibilities
What we will cover
NSTextStorage
Text Kit
Core Text
Core Graphics
Text Kit
UILabel UITextView UITextField
Text KitClasses
NSTextStorage
What? (text & attributes)
NSLayoutManager
How? (glyphs & location)
NSTextContainer
Where? (areas)
Text KitUse defaults or provide your own classes
textStorage = [NSTextStorage new]; layoutManager = [NSLayoutManager new]; textContainer = [[NSTextContainer alloc] initWithSize:size]; [layoutManager addTextContainer:textContainer]; [textStorage addLayoutManager:layoutManager]; !
textView = [[UITextView alloc] initWithFrame:frame textContainer:textContainer];
Text KitNSTextStorage
- (void)processEditing { [_backingStore beginEditing]; // Custom editing [_backingStore endEditing]; [super processEditing]; }
• NSMutableAttributedString subclass • Subclass to provide custom editing
Text KitUsing images in NSTextStorage
(void)replaceLettersInRange:(NSRange)range { [backingStore.string enumerateSubstringsInRange:range options:NSStringEnumerationByComposedCharacterSequences usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) { ! NSTextAttachment *textAttachment = [NSTextAttachment new]; textAttachment.image = [self imageForString:substring]; NSAttributedString *attributed = [NSAttributedString attributedStringWithAttachment:textAttachment]; [backingStore replaceCharactersInRange:substringRange withAttributedString:attributed]; ! }]; }
Demo
github.com/NSBarcelona/CandyCrushKeyboard
UIViewController Transitions
UIViewController Transitions
• Presentations and dismissals • UINavigationController • UITabBarController • UICollectionViewController layout-to-layout
Customizable transitions
Container view
View B
UIViewController TransitionsThe container view
UIViewController A UIViewController B
View A
UIViewController TransitionsReturning the transition animation
- (id <UIViewControllerAnimatedTransitioning>)navigationController: (UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC { id<UIViewControllerAnimatedTransitioning> animator = [MyAnimationController new]; return animator; }
UIViewController TransitionsAnimating the transition
- (void)animateTransition:(id <UIViewControllerContextTransitioning>)context { ! UIViewController *fromVC = [context viewControllerForKey:UITransitionContextFromViewControllerKey]; UIViewController *toVC = [context viewControllerForKey:UITransitionContextToViewControllerKey]; UIView *container = context.containerView; [container insertSubview:toViewController.view aboveSubview:fromViewController.view]; ! // Prepare for animation ! NSTimeInterval duration = [self transitionDuration:context]; [UIView animateWithDuration:duration animations:^{ // Animations } completion:^(BOOL finished) { // Cleanup and restore state [context completeTransition:YES]; }]; }
Demo
github.com/NSBarcelona/Transictures
Adding iCloud to Core Data
–CNBC in 2012
“…the average [US] household has 1.6 Apple devices.”
iCloud
• Using iCloud in iOS 5-6 is a bug • Sync network setup (!) • Limited APIs • Poor support for account changes • Unreliability
• In iOS 7 it’s actually usable
iCloud
1. Add iCloud to Core Data 2. Respond to changes 3. Respond to account changes
Core Data with iCloud in 3 steps
iCloudAdding iCloud to Core Data
NSDictionary *options = @{ NSPersistentStoreUbiquitousContentNameKey : @"name" } ![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:url options:options error:&error];
iCloudResponding to changes
NSPersistentStoreDidImportUbiquitousContentChangesNotification !![moc performBlockAndWait:^{ [moc mergeChangesFromContextDidSaveNotification:notification]; }];
iCloudResponding to account changes
NSPersistentStoreCoordinatorStoresWillChangeNotification !!dispatch_sync(dispatch_get_main_queue(), ^{ // Prepare UI }); [moc performBlockAndWait:^{ NSError *error = nil; if ([moc hasChanges]) { [moc save:&error]; } [moc reset]; }];
iCloudResponding to account changes
NSPersistentStoreCoordinatorStoresDidChangeNotification !!dispatch_sync(dispatch_get_main_queue(), ^{ // Update UI });
Demo
github.com/NSBarcelona/CloudPhotos
The App Store Receipt
–James Wilson (Engineering Manager for the App Store in OS X) at WWDC 2013, about verifying the App Store receipt
“This is doable.”
App Store Receipt
1. Get the receipt data 2. Verify the receipt signature 3. Get the receipt fields 4. Verify the receipt hash 5. Get in-app purchases (optional)
Verification in 5 steps
App Store ReceiptGetting the receipt data
const char *cpath = [[path stringByStandardizingPath] fileSystemRepresentation]; FILE *fp = fopen(cpath, "rb"); if (!fp) return nil; !PKCS7 *p7 = d2i_PKCS7_fp(fp, NULL); fclose(fp); if (!p7) return nil; !NSURL *certificateURL = [[NSBundle mainBundle] URLForResource:@"AppleIncRootCertificate" withExtension:@"cer"]; NSData *certificateData = [NSData dataWithContentsOfURL:certificateURL]; if ([self verifyPCKS7:p7 withCertificateData:certificateData]) { struct pkcs7_st *contents = p7->d.sign->contents; if (PKCS7_type_is_data(contents)) { ASN1_OCTET_STRING *octets = contents->d.data; data = [NSData dataWithBytes:octets->data length:octets->length]; } } PKCS7_free(p7);
App Store ReceiptVerifying the receipt signature
int result = 0; OpenSSL_add_all_digests(); // Required for PKCS7_verify to work X509_STORE *store = X509_STORE_new(); if (store) { const uint8_t *certificateBytes = (uint8_t *)(certificateData.bytes); X509 *certificate = d2i_X509(NULL, &certificateBytes (long)certificateData.length); if (certificate){ X509_STORE_add_cert(store, certificate); BIO *payload = BIO_new(BIO_s_mem()); result = PKCS7_verify(container, NULL, store, NULL, payload, 0); BIO_free(payload); X509_free(certificate); } } X509_STORE_free(store); EVP_cleanup();
App Store ReceiptGetting the receipt fields
[RMAppReceipt enumerateASN1Attributes:asn1Data.bytes length:asn1Data.length usingBlock:^(NSData *data, int type) { const uint8_t *s = data.bytes; const NSUInteger length = data.length; switch (type) { case 2: bundleIdData = data; _bundleId = RMASN1ReadUTF8String(&s, length); break; case 3: appVersion = RMASN1ReadUTF8String(&s, length); break; case 4: opaqueValue = data; break; case 5: hash = data; break; case 17: { RMAppReceiptIAP *purchase = [[RMAppReceiptIAP alloc] initWithASN1Data:data]; [purchases addObject:purchase]; break; } case 19: originalAppVersion = RMASN1ReadUTF8String(&s, length); break; case 21: expirationDate = [RMAppReceipt formatRFC3339String:RMASN1ReadIA5SString(&s, length)]; break; } }];
App Store ReceiptVerifying the receipt hash
NSUUID *uuid = [[UIDevice currentDevice] identifierForVendor]; unsigned char uuidBytes[16]; [uuid getUUIDBytes:uuidBytes]; !NSMutableData *data = [NSMutableData data]; [data appendBytes:uuidBytes length:sizeof(uuidBytes)]; [data appendData:opaqueValue]; [data appendData:bundleIdData]; !NSMutableData *expectedHash = [NSMutableData dataWithLength:SHA_DIGEST_LENGTH]; SHA1(data.bytes, data.length, expectedHash.mutableBytes); !BOOL verified = [expectedHash isEqualToData:hash];
App Store ReceiptGetting the in-app purchases
[RMAppReceipt enumerateASN1Attributes:asn1Data.bytes length:asn1Data.length usingBlock:^(NSData *data, int type) { const uint8_t *p = data.bytes; const NSUInteger length = data.length; switch (type) { case 1701: quantity = RMASN1ReadInteger(&p, length); break; case 1702: productId = RMASN1ReadUTF8String(&p, length); break; case 1703: transactionIdentifier = RMASN1ReadUTF8String(&p, length); break; case 1704: purchaseDate = [RMAppReceipt formatRFC3339String:RMASN1ReadIA5SString(&p, length)]; case 1705: originalTransactionId = RMASN1ReadUTF8String(&p, length); break; case 1706: originalPurchaseDate = [RMAppReceipt formatRFC3339String:RMASN1ReadIA5SString(&p, length)]; break; case 1708: subscriptionExpirationDate = [RMAppReceipt formatRFC3339String:RMASN1ReadIA5SString(&p, length)]; break; case 1711: webOrderLineItemID = RMASN1ReadInteger(&p, length); break; case 1712: cancellationDate = [RMAppReceipt formatRFC3339String:RMASN1ReadIA5SString(&p, length)]; break; } }];
Demo
github.com/robotmedia/RMStore
About me
Jordi Giménez
• CTO at Mobile Jazz
• Co-organizer of NSBarcelona
• iOS and Android developer
• High-availability, high-scalability
• IT Security
Speech Synthesis with AV FoundationAV Foundation framework provides essential services for working with time-based audiovisual media.
Play, capture, edit, or encode media.
AV Foundation
• AVFoundation allows provides a convenient interface to the speech synthesizer
Speech synthesis
AVSpeechSynthesizer *synthesizer = [AVSpeechSynthesizer new]; AVSpeechUtterance *utterance = [AVSpeechUtterance speechUtteranceWithString:@"Hello world!"]; [synthesizer speakUtterance:utterance];
JavaScriptCoreEvaluate JavaScript in your iOS applications
JavaScriptCore
• New Objective-C interface • Allows Objective-C Language Binding • Good for JSON parsing/transformation • Platform independent code
JavaScript Execution
// make an execution context JSContext *context = [[JSContext alloc] initWithVirtualMachine: [[JSVirtualMachine alloc] init]]; !
// read and write variables context[@"a"] = @5; // write global variables JSValue *aValue = context[@"a"]; // read global variables double a = [aValue toDouble];
JavaScript Execution
// declare a function [context evaluateScript:@"var square = function(x) {return x*x;}”]; !
// run a function JSValue *squareFunction = context[@"square"]; JSValue *result = [squareFunction callWithArguments:@[@3]];
JavaScript Execution
// declare a function as an Objective-C block context[@"square"] = ^(int x) { return x*x; };
Networking APIs
New networking APIs
• Multitasking: background execution of network tasks • AirDrop: data transfer between nearby devices • Multipeer connectivity: message passing between ad-hoc groups of
people
Multitasking
• iOS applications can’t generally run in the background, in order to save battery and boost performance
• UIBackgroundModes specify when the app should wake up • audio • location • newsstand-content • external-accessory • bluetooth-central • bluetooth-peripherial • fetch • remote-notification
Multitasking
// 1. Specify `fetch` in UIBackgroundModes in Info.plist to wake up the application at intervals. !// 2. Give an interval hint: [[UIApplication sharedApplication] setMinimumBackgroundFetchInterval:UIApplicationBackgroundFetchIntervalMinimum]; !// 3. Handle fetch wakeup -(void) application:(UIApplication *)application performFetchWithCompletionHandler:(void(^) (UIBackgroundFetchResult))completionHandler { // fetch content from the network if(newContent) { completionHandler(UIBackgroundFetchResultNewData); } else { completionHandler(UIBackgroundFetchResultNoData); } }
Background fetch: wake up at intervals
Multitasking
// 1. Specify `remote-notification` in UIBackgroundModes in Info.plist to wake up the application upon reception of push notifications with `content-available=1` attribute. !// 2. Handle fetch wakeup - (void) application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo performFetchWithCompletionHandler:(void(^)(UIBackgroundFetchResult))completionHandler { if([[userInfo objectForKey:@"content-available"] intValue] != 1) { completionHandler(UIBackgroundFetchResultNoData); // no content-available! return; } // fetch content from the network if(newContent) { completionHandler(UIBackgroundFetchResultNewData); } else { completionHandler(UIBackgroundFetchResultNoData); } }
Remote notifications: wake up on server demand
Multitasking
Transferring files can be a problem: • Intermittent connectivity • User switching applications • Network conditioned operations (eg. wifi only)
Background Transfer Service
Multitasking
Uploads/downloads files even if the application is in background !
1. Make an NSURLSession with the desired NSURLSessionConfiguration 2. Provide a session identifier and delegate 3. Initiate a task 4. Delegate methods will be called upon progress/completion
Background Transfer Service
Multitasking
The application might be killed while in the background. !
To deal with background mode, also implement -application:handleEventsForBackgroundURLSession:completionHandler: like this: !
1. Look at the session identifier provided by the system 2. Make an NSURLSession with the desired NSURLSessionConfiguration,
matching the settings for that identifier, with a delegate 3. Delegate methods will be called to notify completion
Background Transfer Service
AirDrop
AirDrop
AirDrop lets users share photos, documents, URLs (including custom schemes), and other kinds of data via Wifi/Bluetooth
!
(See Apple’s AirDropSample)
AirDrop
1. Implement a class with the UIActivityItemSource protocol Provides:
• a URL with custom scheme or • an UTI + NSData.
2. Display a UIActivityViewController to handle your class instance
!
UIActivityViewController already existed before to share data between apps, AirDrop was added
Sending a file
AirDrop
• Add the document types and URL schemes you want to support (Xcode Target > Info) !
!
!
!
!
!
No matter where the file comes from (local or AirDrop) you will receive it the same way.
Receiving a file
AirDrop
// handle incoming URLs/files - (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation { if ([url.scheme isEqualToString:@"my-custom-scheme"]) { // handle custom scheme URL } else { // read file at URL } return YES; }
Receiving a file
Multipeer connectivity
Multipeer connectivity
• Allows to make ad-hoc groups of up to 8 devices in order to share data (NSData, streams)
• Ideal for games or other kinds of data transfer on the spot
iBeacons
iBeacons
• iBeacons are Bluetooth Low Energy devices emitting an identifier • CoreLocation integrates natively with iBeacons to provide regions • Applications can be notified when entering/leaving a region (even in the
background) with very little power consumption !
• Useful for: • Locating areas at a retail store • Augmentation of museum • Geocaching/scavenger hunt games • Tourism
iBeacons
// tell location manager to start monitoring for the beacon region region = [[CLBeaconRegion alloc] initWithProximityUUID:uuid identifier:@"ibeacon.test"]; !
[locationManager startMonitoringForRegion:region]; [locationManager startRangingBeaconsInRegion:region]; !
// listen for location manager updates -(void)locationManager:(CLLocationManager*)manager didRangeBeacons:(NSArray*)beacons inRegion:(CLBeaconRegion*)region { NSLog(@"Beacons found: %@", beacons); }
Listen for iBeacons
iBeacons
// start the peripheral manager, tells about Bluetooth state peripheralManager = [[CBPeripheralManager alloc] initWithDelegate:self queue:nil options:nil]; !// listen for bluetooth peripheral updates -(void)peripheralManagerDidUpdateState:(CBPeripheralManager*)peripheral { if (peripheral.state == CBPeripheralManagerStatePoweredOn) { // makes a region describing this device CLBeaconRegion *advertisingRegion = [[CLBeaconRegion alloc] initWithProximityUUID:uuid major:33 minor:44 identifier:@"ibeacon.test"]; // gets this device's data to use as beacon NSDictionary* beaconData = [advertisingRegion peripheralDataWithMeasuredPower:nil]; // advertises [self.peripheralManager startAdvertising:beaconData]; } else if (peripheral.state == CBPeripheralManagerStatePoweredOff) { [self.peripheralManager stopAdvertising]; } }
Advertising your iDevice
Wrap up
• Speech synthesis • JavaScript evaluation • Networking in the background
• Background fetch • Remote notification background mode • Background Transfer Service
• AirDrop & Multi-peer connectivity • iBeacons
So… What’s new in iOS 7?
• https://developer.apple.com/ios7/ • https://developer.apple.com/library/prerelease/ios/releasenotes/General/
WhatsNewIniOS/Article
OK, you want the full list
Thank you! !
Check out our sample code at: github.com/nsbarcelona
Hermes Pique!@hpique
Jordi Gimé[email protected]