ストリーミングはほとんどのブラウザと
Developerアプリで視聴できます。
-
クイックメモの採用
Appをクイックメモにリンクして、コンテンツとノート、そしてノートとコンテンツをすばやく結びつける方法を確認しましょう。NSUserActivityを介してクイックメモがAppのコンテンツを認識しリンクする方法と、AppへのAPIの導入方法を紹介します。また、クイックメモをサポートするための要件、メリット、機能についても紹介します。AppでNSUserActivityのメリットをすべて活かすためのガイダンスやベストプラクティスについてもお伝えします。
リソース
関連ビデオ
WWDC18
-
ダウンロード
ニッキー・ブラウアーです ペンシル&ペーパーチームの エンジニアです 今日はQuick Noteの 導入方法について
Quick Noteは新しく システム統合したノート 単にiOSやmacOSで ノートを取るだけでなく 複数のAppやウェブの コンテンツを一つに統合
これでNoteをどこへでも 持ち運べます 優れているのは既存のAPIが 利用可能という事 NSUserActivityです Handoffなどで採用 聞きなじみがあるでしょう
今日は実際にQuick Noteを デモで紹介します まず基本動作について お話します そしてNSUserActivityの 導入方法も その後いくつか事例も ぜひ役立てて下さい
Quick Noteの新機能について これからお話します 例としてー Apple Fitness+について 調べます 登録はまだですが アクションプラン無しはイヤです Notes Appに切り替える代わりに ペンシルで画面右下から スワイプアップすると 新しいQuick Noteが出現して メモを取り始めることができます このAppleのサイトには 私が必要な情報が全てあり
Quick Noteの上部には リンク追加のメニューが出ているので このウェブサイトへのリンクを 追加しておいて 後で簡単にこのコンテンツに 戻ってくることができます
Quick Noteは picture-in-pictureの様に デバイスのどの角にも動かせ ピンチでサイズを変更して 大小好きな大きさにできます
書き終わったらー 左上のDoneボタンで完了です でも今はまだ追加するものがあるので UIを右にスワイプして スクリーンのサイドに隠します ウェブサイトだけでなく 当然他のAppとも連携します MapsでHIITワークアウト用の いい場所を見つけました さっきのノートを出し このロケーションを追加します 書き込むスペースを広げるには ツールバーのNotesボタンをタップして Notes Appでそのページを開きます
ここでは、画像やリンクを 描画する機能を利用します
私が先程追加したこのリンクは 単なる古いリンクではありません もちろんタップすれば SafariやMapsへ飛ぶでしょう でもこれらのAppから Quick Noteのサジェスチョンによって ノートに戻ることができるのです 先程のApple Fitness+の サイトへ戻ると Quick Note Suggestions UI が右下に表示されます これをタップすれば 元の場所に戻って そして週4日から5日 HIITワークアウトと追加できます
今はiPadで書きましたが Macとも連携しています
先程のApple Fitness+の ページを開くと Quick Note Suggestions UI がMacでも現れます ここをクリックすれば Notes App の 該当ページを直接開きます Quick Noteを紹介しました 仕組みを見てみましょう NSUserActivityオブジェクトは Appの状態を保存し 後で再利用する方法を提供します UserActivityオブジェクトは 現状の動作を把握する為のもので ウェブの閲覧やAppの表示内容など そしてそうした履歴を システムに保存します
システムは受け取った履歴を Handoffなどに送ります
Quick Noteのリンクも このシステムに依存しています
アクティビティーは Handoff Spotlight Reminders に加えて Quick Noteへも送られます これが Noteのメニューに 追加するリンクが表示されたり Quick Note Suggestionsが 起動される仕組みです
NSUserActivityには 3つのプロパティがあります AppのコンテンツとQuick Noteを リンクする永続的な識別子です エコシステムを構成するには 1つ以上のプロパティが必要です targetContentIdentifierと persistentIdentifier そしてwebpageURLです どれを選択するかは サポートしたい機能で決まります
targetContentIdentifierも ステートのリストアで使われます このプロパティはiPadでの優れた マルチタスク体験を提供します
persistentIdentifierは システムのSpotlightインデックスで Appのコンテンツ照会に 使われます webpageURLはHandoffの Webフォールバックにも使用されます Quick Noteのリンクを使うには いくつかのプロパティと 識別子が必要です あらゆるデバイスで利用するために ユニークでグローバルな識別子である 必要があります 時間が経過してもそのコンテンツが 十分安定して機能する必要があります ユニークでグローバル、そして安定した アクティビティの識別子が Quick Note Suggestionsを 有効にします Apple Fitness+のサイトを再び開くと Quick Note Suggestions UIが 出る理由も リンク内の識別子が 1時間前あるいは半年前に作られても ウェブサイト上の識別子に 合致するからです
NSUserActivityを 導入するステップは3つ サポートするアクティビティを あなたのAppのInfo.plistで宣言し 折々のタイミングで 画面に表示されている内容を表す ユーザーアクティビティを 作成そして登録します そして受信した要求を処理して アクティビティの続きを実行可能とします
この要求はQuick Noteのリンクや 他のデバイスからかもしれません あなたのアプリが対応する アクティビティタイプを キー NSUserActivityTypes で Info.plist ファイルに宣言します
システムはそのキーの情報を使用して Appが特定のユーザーアクティビティを 処理できるかどうかを判断します NSUserActivity オブジェクトの作成には plistに登録済のactivity type stringsと タイトルを指定します そして説明した3つの識別子から 1つ以上を指定します これらの識別子は全て Quick Noteで有効です 例えばiPad用のAppで ステートのリストアを サポートする場合… targetContentIdentifier を設定し userInfoプロパティに アクティビティ継続の為に必要な Appのステート情報をセットします
そしてこれをresponderに アタッチします
マニュアルでAppのアクティビティを 登録する代わりに システムにやらせる事ができます responderのactivityに設定すれば オブジェクトは UIKitかAppKitが管理します
NSUserActivityは クロスプラットフォームなので このコードは iOSとmacOSで共に有効です 最後のステップは 受信したアクティビティからの App内の状態のリストアです リンクがタップされると Quick NoteがAppを起動し UIWindowSceneDelegate の scene の willContinueUserActivityWithType を 呼び出します アプリアクティビティを受信している事の フィードバックをここで出せます
Quick Noteが Appのアクティビティを scene(continue userActivity:) で提供します ここで view controllersやviewの 設定を行い userInfo辞書を使ってリストアを行い アクティビティを継続させます Handoffの場合 デバイスが接続できない時は システムが呼び出すのはsceneの (didFailToContinueUserActivityWithType) ここでエラーメッセージを出します このメソッドはQuick Noteでは 呼ばれませんが NSUserActivityを包括的に採用するために 実装することをお勧めします
macOS Appでは同等の application (willContinueUserActivityWithType)と application(continue userActivity) そして application (didFailToContinueUserActivityWithType) これらをAppのdelegateで実装します NSUserActivity対応の詳細は WWDC 2014の "Adopting Handoff on iOS 8 and OS X" を参照してください
NSUserActivityは多くの機能を司る ゲートウェイです
Quick Noteに対応するための作業は これが全てです Handoffはデフォルトで有効 その他はopt-inです あなたのAppを さらにパワーアップしましょう Appのドキュメントに リマインダーの機能を付けたり Appから投稿したブログを Spotlightで表示したり マルチウィンドウ処理を 改善することができます。
最新資料や WWDCの映像で 詳細を確認してください それでは最後に Quick Noteに対応するための NSUserActivityの導入について ベストプラクティスを見てみましょう 4つの挙動について話します それぞれをAppに統合する理由と 方法についてお話します
titleのプロパティは人間が可読な アクティビティの文字列です
リンクを追加するメニューの中に 表示されます このように タイトルはー コンテンツを 簡潔に説明したもので 文書やアイテムの名前を そのまま使う事を推奨します
識別子をユニークかつ 安定したものにするため
デバイス内にしかないデータは 避けましょう 例えばこの写真の識別子が ローカルのファイルパスである場合 このリンクはこれを作成した デバイスのみで使用可能となります session IDのように一時的なものや 特定の表示用のプロパティは 避けましょう 写真のタイトルは一意に思えますが それが変更できる場合 後でこのコンテンツに戻った時 まだそのままの保証はありません
長期的に考えれば 写真にUUIDを使えば Quick Noteリンクの リストアに役立ちます コンテンツが移動していても 大丈夫です URLはAppのコンテンツの一意の 識別子にすることができますが 一時的な状態情報が 含まれていることが多く 前述の識別子のガイドラインに 違反しています Quick NoteではwebpageURLよりも targetContentIdentifierと persistentIdentifierを優先します webpageURLも ガイドラインに沿っていれば 使用可能です Appが状態のリストアとSpotlight 両方にNSUserActivityを使う場合 targetContentIdentifierと persistentIdentifierに 同じ値を使用します あなたのAppをサポートする ウェブサイトがある場合 第二のフォールバック識別子として URLを追加します Appがインストールされていない場合 リンク先を代わりに開きます
もう1つ重要な事は NSUserActivityを常に最新に設定する事 起こっていることを常に更新します
titleと識別子で 常に正確に把握できるように 違う写真を選択した時など 変更を検知した時に更新します
アクティビティインスタンスの 再利用は推奨しません 写真の追加ような新コンテンツには 新しいアクティビティを作成しましょう
サンプルコードで示した様に viewControllersやviewなどの responderにアクティビティを付けて UIKitとAppKitに現在のAppの アクティブティを処理させましょう responderへの添付が 正しく動作しない場合は 適切なタイミングでbecomeCurrent()と resignCurrent()を呼び出すことにより 現在のAppアクティビティを 手動で管理できます 例えば写真の表示が終了したら Appは現在のアクティビティで resignCurrent()を呼び出し 新しい写真が選択されたら Appは新しいアクティビティで becomeCurrent()を呼び出します
パフォーマンスを向上させるには アクティビティの”needsSave"を使います Appでアクティビティを 適切にリストアするには 特定のビュープロパティが 必要な場合があります 例えばマップを表示するときの 位置やズーム これらのプロパティはアクティビティと 一緒に渡すことができますが すべてのジェスチャの後に更新すると オーバーヘッドがあります そこで アクティビティを 更新する代わりに needsSaveの値をtrueに設定すると システムがアクティビティをQuick Noteか Handoffに送信する必要がある場合に デリゲートコールバック userActivityWillSaveが呼び出されるので Appは必要な時にだけ 全てのプロパティを更新できるようになります
このコールバックでuserInfo辞書を更新して アクティビティのリストアに必要な プロパティを含めることができます
対応すべき互換性の問題が いくつかあります もしAppが更新されたら? このノートには1つのAppから 2つのリンクが追加されています このリンクはそれぞれデバイス上の 新旧のバージョンのAppから取得されました まったく問題ありませんが リンクは引き続き機能する必要があります 互換性を維持する為には 旧バージョンで保存した アクティビティのリストアに 対応する必要があります 新バージョンで作成したアクティビティの リストアは「正しく」失敗しましょう アクティビティのバージョン管理、 辞書を使用した場合のキーの欠落や 未知のキーのハンドリングなどで うまくサポートできる可能性があります コンテンツがもう存在しない場合は?
アクティビティのリンク先のコンテンツが 削除または移動された可能性があります Appに戻った時に 削除された場合は エラーメッセージを表示し コンテンツが移動された場合は リダイレクトします AppにQuick Noteを導入すると ノートの取り方が変わります このシステムでユーザーと コンテンツそしてAppの 繋がりが向上します NSUserActivityを 使用している事を確認してください 今こそ既存のコードを再検討して 磨き上げる絶好の機会です
またユニークでグローバル そして安定した識別子を使います respondersで アクティビティを設定して システムがAppの現在のNSUserActivityを 管理できるようにします ありがとう Quick Note等を活かしたー Appを楽しみにしています パーカッシブな音楽
-
-
16:57 - How to adopt NSUserActivity to support Quick Note
// Create the NSUserActivity and describe the content or user activity let activity = NSUserActivity(activityType: "com.myapp.MyActivityType") activity.title = document.title // Set one or more of: // .targetContentIdentifier // .persistentIdentifier // .webpageURL activity.targetContentIdentifier = "uniqueGlobalStableIdentifier" // Set userInfo to save app-specific state information activity.userInfo = ["myKey": …] // Attach it to a view controller, window, or other responder; let the system make it current when needed viewController.userActivity = activity
-
17:02 - Handle NSUserActivity continuation in your window scene delegate or app delegate - iOS
class SceneDelegate: UIResponder, UIWindowSceneDelegate { func scene(_ scene: UIScene, willContinueUserActivityWithType userActivityType: String) { // show user feedback while waiting for the NSUserActivity to arrive } func scene(_ scene: UIScene, continue userActivity: NSUserActivity) { // set up view controllers and views to continue the activity } func scene(_ scene: UIScene, didFailToContinueUserActivityWithType userActivityType: String, error: Error) { // show error about failing to continue an activity } … }
-
17:06 - Handle NSUserActivity continuation in your window scene delegate or app delegate - macOS
class AppDelegate: NSObject, NSApplicationDelegate { func application(_ application: NSApplication, willContinueUserActivityWithType userActivityType: String) -> Bool { // show user feedback while waiting for the NSUserActivity to arrive return true } func application(_ application: NSApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([NSUserActivityRestoring]) -> Void) -> Bool { // set up view controllers or documents to continue the activity return true } func application(_ application: NSApplication, didFailToContinueUserActivityWithType userActivityType: String, error: Error) { // show error about failing to continue an activity, if appropriate } … }
-
17:26 - Improve performance with needsSave
activity.needsSave = true … func userActivityWillSave(_ userActivity: NSUserActivity) { userActivity.userInfo = [ "center" : visibleFrame.middle "zoomScale" : scrollView.zoomScale ] }
-
-
特定のトピックをお探しの場合は、上にトピックを入力すると、関連するトピックにすばやく移動できます。
クエリの送信中にエラーが発生しました。インターネット接続を確認して、もう一度お試しください。