UIKit 
Getting started with Handoff 
How can I do it? 
Yuichi Yoshida 
Chief engineer, DENSO IT Laboratory, Inc. 
#yidev20140927 
@sonson_twit 
© 2014 Yuichi Yoshida, all rights reserved. Redistribution or public display not permitted without written permission from Yuichi Yoshida.
自己紹介 
2tchの中の人 
• iOS好きです 
• 2tch(2ちゃんねるビューア) 
• iOS SDK Hacksなど 
• 研究 
• コンピュータビジョン 
• 機械学習 
• 研究・開発 
• 画像検索サービス 
• 車向けのサービスやハードウェア
Demo 
2tch version 6.3.1
What is Handoff? 
継続って訳すのやめて欲しい
Handoffの種類 
• Safariを呼ぶ 
• URLを渡すだけ 
• ネイティブアプリケーション 
• 受信側にコードが必要 
• インストールされていれば自動起動する 
• Safariからネイティブアプリケーションを呼ぶ 
• 署名した対応アプリ一覧JSONが必要
?
準備 
• 対応ハードウェアを買う 
• MacBook Air (Mid 2011以降) 
• MacBook Pro (Mid 2012以降) 
• Retina MacBook Pro (全機種) 
• iMac (Late 2012以降) 
• Mac Mini (Mid 2011以降) 
• Mac Pro (Late 2013以降) 
• http://www.ipadmod.netより 
• iOS 
• iPhone 5以降、iPad(第4世代)、iPad Air、iPad mini、iPad 
mini Retinaディスプレイモデル、iPod touch(第5世代)
準備 
• iCloudに登録する 
• Bluetoothをオンにする 
• Wi-Fiをオンにする
準備 
• iCloudに登録する 
• Bluetoothをオンにする 
• Wi-Fiをオンにする
Demo 
Safariで試す
ネイティブアプリからSafariへ 
• とっても簡単 
• NSUserActivityクラス 
• - webpageURL
NSUserActivity 
@interface ViewController () { 
NSUserActivity *_activity; 
} 
@end 
@implementation ViewController 
- (void)viewDidLoad { 
[super viewDidLoad]; 
_activity 
= [[NSUserActivity alloc] 
initWithActivityType:@"com.sonson.HandoffSample"]; 
_activity.webpageURL 
= [NSURL URLWithString:@"http://www.apple.com"]; 
_activity.title = @"Browsing"; 
[_activity becomeCurrent]; 
} 
@end
[_activity becomeCurrent];
[_activity invalidate];
ネイティブアプリケーション 
• Info.plist 
• NSUserActivityTypesに受け取る識別子を追加 
• 逆ドメイン形式 
• com.sonson.HandoffSample 
• UIApplicationDelegate(NSApplicationDelegate) 
• application:willContinueUserActivityWithType: 
• application:didFailToContinueUserActivityWithType:error: 
• application:continueUserActivity:restorationHandler: 
• OSXの場合 
• 署名必須(Developer IDでもよいみたい)
NSUserActivity 
_activity 
= [[NSUserActivity alloc] 
initWithActivityType:@"com.sonson.OSX.HandoffSample"]; 
_activity.title 
= @"Browsing"; 
_activity.userInfo 
= @{@"ImageSize":@(_imageBinary.length)}; 
[_activity becomeCurrent];
UIApplicationDelegate 
- (BOOL)application:(NSApplication *)application 
willContinueUserActivityWithType:(NSString *)activityType { 
if ([activityType isEqualToString:@"com.sonson.OSX.HandoffSample"]) 
return YES; 
return NO; 
} 
- (BOOL)application:(NSApplication *)application 
continueUserActivity:(NSUserActivity *)userActivity 
restorationHandler:(void(^)(NSArray *restorableObjects))handler { 
// Obtained information from userInfo. 
NSNumber *imageSize = userActivity.userInfo[@"ImageSize"]; 
handler(@[]); // restore view controllers 
return YES; 
}
ViewController restoration 
• UIResponder 
• - 新しいデリゲートメソッド 
• - restoreUserActivityState: 
• void(^)(NSArray *restorableObjects) 
• restoreするUIResponderのサブクラスをつっこむ 
• 自動的にrestoreUserActivityState:が呼ばれる 
• 引数はNSUserActivityオブジェクト
Restoration 
- (BOOL)application:(UIApplication *)application continueUserActivity: 
(NSUserActivity *)userActivity 
restorationHandler: 
(void(^)(NSArray *restorableObjects))restorationHandler { 
// get or create view controller objects. 
id viewControllerA = nil; // left pain 
id viewControllerB = nil; // right pain 
// start to restore 
restorationHandler(@[viewControllerA, viewControllerB]); 
return YES; 
} 
@implementation ViewControllerAClass 
- (void)restoreUserActivityState:(NSUserActivity *)activity { 
// restore left pain view using NSUserActivity object 
} 
@end 
@implementation ViewControllerBClass 
- (void)restoreUserActivityState:(NSUserActivity *)activity { 
// restore right pain view using NSUserActivity object 
} 
@end
うまくいかない? 
Bug? 
• 対応機種ですか? 
• iCloudは同じアカウントになっていますか? 
• NSUserActivityのインスタンスはありますか? 
• 他の機器とHandoffが混線していませんか?
Further more, Handoff 
Communicate with.…… 
• ブラウザからHandoff経由でアプリを起動する 
• Webページ閲覧中にiOSデバイスのアプリを起動 
• 3つのデータ送受信 
• userInfo 
• iCloud 
• NSStream
Further more, Handoff 
SafariからのHandoff 
• iOS側のentitlementにサーバのドメインを追加 
• JSONを作る 
• JSONに署名する 
• iOSの持つリストに入ってる認証局の証明書が必要 
• 実はApple自身が認証局になってる 
• なのでAppleの開発者の署名でおk 
• httpsで通信できるサーバにJSONを置く 
• ルートに置く必要がある
Further more, Handoff 
大きなデータはどうするか? 
• userInfo 
• NSArray, NSData, NSDate, NSDictionary, NSNull, 
NSNumber, NSSet, NSString, NSURL 
• iCloud 
• UIDocumentが自動的にNSUserActivityを生成 
• CFBundleDocumentTypes 
• NSUbiquitousDocumentUserActivityType 
• NSStream 
• 簡単
Further more, Handoff 
送信側 
_activity 
= [[NSUserActivity alloc] 
initWithActivityType:@"com.sonson.OSX.HandoffSample"]; 
_activity.title 
= @"Browsing"; 
_activity.userInfo 
= @{@"ImageSize":@(_imageBinary.length)}; 
_activity.supportsContinuationStreams = YES; 
_activity.delegate = self; 
[_activity becomeCurrent];
Further more, Handoff 
受信側 
- (BOOL)application:(NSApplication *)application 
continueUserActivity:(NSUserActivity *)userActivity 
restorationHandler:(void(^)(NSArray *restorableObjects))restorationHandler { 
[userActivity getContinuationStreamsWithCompletionHandler: 
^(NSInputStream *inputStream, NSOutputStream *outputStream, NSError *error) { 
if (error == nil) { 
_inputStream = inputStream; 
_outputStream = outputStream; 
[_outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] 
forMode:NSDefaultRunLoopMode]; 
[_outputStream open]; 
[_inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] 
forMode:NSDefaultRunLoopMode]; 
[_inputStream open]; 
// communicate... 
} 
else { 
// error handling 
} 
}]; 
return YES; 
}
Further more, Handoff 
NSUserActivityDelegate 
- (void)userActivity:(NSUserActivity *)userActivity 
didReceiveInputStream:(NSInputStream *)inputStream 
outputStream:(NSOutputStream *)outputStream { 
_outputStream = outputStream; 
[_outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] 
forMode:NSDefaultRunLoopMode]; 
[_outputStream open]; 
// send data 
}
Demo 
Handoff from Safari 
Send a picture via NSStream
まとめ 
You get to try it. 
• Handoff 
• 使えるデバイスは限定される 
• SafariにURLを渡すHandoff 
• ネイティブアプリケーション同士のHandoff 
• Safariから渡すHandoff 
• Handoffの通信方法
More Information 
Yuichi Yoshida 
http://github.com/sonsongithub/ 
@sonson_twit 
sonson.jp 
http://sonson.jp 
Apple Handoff プログラミングガイド 
https://developer.apple.com/jp/devcenter/ios/library/ 
documentation/HandoffProgrammingGuide.pdf

Getting started with Handoff

  • 1.
    UIKit Getting startedwith Handoff How can I do it? Yuichi Yoshida Chief engineer, DENSO IT Laboratory, Inc. #yidev20140927 @sonson_twit © 2014 Yuichi Yoshida, all rights reserved. Redistribution or public display not permitted without written permission from Yuichi Yoshida.
  • 2.
    自己紹介 2tchの中の人 •iOS好きです • 2tch(2ちゃんねるビューア) • iOS SDK Hacksなど • 研究 • コンピュータビジョン • 機械学習 • 研究・開発 • 画像検索サービス • 車向けのサービスやハードウェア
  • 3.
  • 4.
    What is Handoff? 継続って訳すのやめて欲しい
  • 5.
    Handoffの種類 • Safariを呼ぶ • URLを渡すだけ • ネイティブアプリケーション • 受信側にコードが必要 • インストールされていれば自動起動する • Safariからネイティブアプリケーションを呼ぶ • 署名した対応アプリ一覧JSONが必要
  • 9.
  • 10.
    準備 • 対応ハードウェアを買う • MacBook Air (Mid 2011以降) • MacBook Pro (Mid 2012以降) • Retina MacBook Pro (全機種) • iMac (Late 2012以降) • Mac Mini (Mid 2011以降) • Mac Pro (Late 2013以降) • http://www.ipadmod.netより • iOS • iPhone 5以降、iPad(第4世代)、iPad Air、iPad mini、iPad mini Retinaディスプレイモデル、iPod touch(第5世代)
  • 11.
    準備 • iCloudに登録する • Bluetoothをオンにする • Wi-Fiをオンにする
  • 12.
    準備 • iCloudに登録する • Bluetoothをオンにする • Wi-Fiをオンにする
  • 13.
  • 14.
    ネイティブアプリからSafariへ • とっても簡単 • NSUserActivityクラス • - webpageURL
  • 15.
    NSUserActivity @interface ViewController() { NSUserActivity *_activity; } @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; _activity = [[NSUserActivity alloc] initWithActivityType:@"com.sonson.HandoffSample"]; _activity.webpageURL = [NSURL URLWithString:@"http://www.apple.com"]; _activity.title = @"Browsing"; [_activity becomeCurrent]; } @end
  • 17.
  • 18.
  • 19.
    ネイティブアプリケーション • Info.plist • NSUserActivityTypesに受け取る識別子を追加 • 逆ドメイン形式 • com.sonson.HandoffSample • UIApplicationDelegate(NSApplicationDelegate) • application:willContinueUserActivityWithType: • application:didFailToContinueUserActivityWithType:error: • application:continueUserActivity:restorationHandler: • OSXの場合 • 署名必須(Developer IDでもよいみたい)
  • 20.
    NSUserActivity _activity =[[NSUserActivity alloc] initWithActivityType:@"com.sonson.OSX.HandoffSample"]; _activity.title = @"Browsing"; _activity.userInfo = @{@"ImageSize":@(_imageBinary.length)}; [_activity becomeCurrent];
  • 21.
    UIApplicationDelegate - (BOOL)application:(NSApplication*)application willContinueUserActivityWithType:(NSString *)activityType { if ([activityType isEqualToString:@"com.sonson.OSX.HandoffSample"]) return YES; return NO; } - (BOOL)application:(NSApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void(^)(NSArray *restorableObjects))handler { // Obtained information from userInfo. NSNumber *imageSize = userActivity.userInfo[@"ImageSize"]; handler(@[]); // restore view controllers return YES; }
  • 22.
    ViewController restoration •UIResponder • - 新しいデリゲートメソッド • - restoreUserActivityState: • void(^)(NSArray *restorableObjects) • restoreするUIResponderのサブクラスをつっこむ • 自動的にrestoreUserActivityState:が呼ばれる • 引数はNSUserActivityオブジェクト
  • 23.
    Restoration - (BOOL)application:(UIApplication*)application continueUserActivity: (NSUserActivity *)userActivity restorationHandler: (void(^)(NSArray *restorableObjects))restorationHandler { // get or create view controller objects. id viewControllerA = nil; // left pain id viewControllerB = nil; // right pain // start to restore restorationHandler(@[viewControllerA, viewControllerB]); return YES; } @implementation ViewControllerAClass - (void)restoreUserActivityState:(NSUserActivity *)activity { // restore left pain view using NSUserActivity object } @end @implementation ViewControllerBClass - (void)restoreUserActivityState:(NSUserActivity *)activity { // restore right pain view using NSUserActivity object } @end
  • 24.
    うまくいかない? Bug? •対応機種ですか? • iCloudは同じアカウントになっていますか? • NSUserActivityのインスタンスはありますか? • 他の機器とHandoffが混線していませんか?
  • 25.
    Further more, Handoff Communicate with.…… • ブラウザからHandoff経由でアプリを起動する • Webページ閲覧中にiOSデバイスのアプリを起動 • 3つのデータ送受信 • userInfo • iCloud • NSStream
  • 26.
    Further more, Handoff SafariからのHandoff • iOS側のentitlementにサーバのドメインを追加 • JSONを作る • JSONに署名する • iOSの持つリストに入ってる認証局の証明書が必要 • 実はApple自身が認証局になってる • なのでAppleの開発者の署名でおk • httpsで通信できるサーバにJSONを置く • ルートに置く必要がある
  • 27.
    Further more, Handoff 大きなデータはどうするか? • userInfo • NSArray, NSData, NSDate, NSDictionary, NSNull, NSNumber, NSSet, NSString, NSURL • iCloud • UIDocumentが自動的にNSUserActivityを生成 • CFBundleDocumentTypes • NSUbiquitousDocumentUserActivityType • NSStream • 簡単
  • 28.
    Further more, Handoff 送信側 _activity = [[NSUserActivity alloc] initWithActivityType:@"com.sonson.OSX.HandoffSample"]; _activity.title = @"Browsing"; _activity.userInfo = @{@"ImageSize":@(_imageBinary.length)}; _activity.supportsContinuationStreams = YES; _activity.delegate = self; [_activity becomeCurrent];
  • 29.
    Further more, Handoff 受信側 - (BOOL)application:(NSApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void(^)(NSArray *restorableObjects))restorationHandler { [userActivity getContinuationStreamsWithCompletionHandler: ^(NSInputStream *inputStream, NSOutputStream *outputStream, NSError *error) { if (error == nil) { _inputStream = inputStream; _outputStream = outputStream; [_outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; [_outputStream open]; [_inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; [_inputStream open]; // communicate... } else { // error handling } }]; return YES; }
  • 30.
    Further more, Handoff NSUserActivityDelegate - (void)userActivity:(NSUserActivity *)userActivity didReceiveInputStream:(NSInputStream *)inputStream outputStream:(NSOutputStream *)outputStream { _outputStream = outputStream; [_outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; [_outputStream open]; // send data }
  • 31.
    Demo Handoff fromSafari Send a picture via NSStream
  • 32.
    まとめ You getto try it. • Handoff • 使えるデバイスは限定される • SafariにURLを渡すHandoff • ネイティブアプリケーション同士のHandoff • Safariから渡すHandoff • Handoffの通信方法
  • 33.
    More Information YuichiYoshida http://github.com/sonsongithub/ @sonson_twit sonson.jp http://sonson.jp Apple Handoff プログラミングガイド https://developer.apple.com/jp/devcenter/ios/library/ documentation/HandoffProgrammingGuide.pdf