ストリーミングはほとんどのブラウザと
Developerアプリで視聴できます。
-
CareKitの新機能
CareKitを使って、豊富な特徴を持つリサーチやケアAppを作成しましょう:表示が新しくなったモジュラーアーキテクチャー、改善されたデータストレージ、iOSのその他のフレームワークとのより緊密な統合を含むヘルスフレームワークの最新情報についてお伝えします。今後も、プライバシーを保護しながらオープンソースコミュニティがCareKitを活用し、デベロッパがデジタルヘルスの限界を押し上げていくことをどう助けるかについてもご説明します。
リソース
関連ビデオ
WWDC20
-
ダウンロード
こんにちは WWDCへようこそ “CareKitの新情報” 私はガヴィ・ローソンです Apple Healthチームのエンジニアで CareKitフレームワークに取り組んでいます 同様にフレームワークの開発に取り組んでいる 同僚のエリックも後ほど参加してくれます 今日はCareKitに追加された アップデートについてお話しします CareKitとは何でしょう? CareKitは優れた医療アプリケーションを 構築するオープンソースのフレームワークで CareKit CareKitUI CareKitStore という 3つの部分に分かれています 各部分はそれ自体のフレームワークであり Swift Package Managerでインポートできます CareKitStoreでは ヘルスフレーバーデータモデルと コアデータ永続化レイヤーを提供します CareKitUIには このデータを 最適に表示する静的ビューがあります CareKitはUIとストアレイヤーを同期させ 2つを結び付けます ストアのデータが変更されると 自動的にビューが更新されます 昨年 Swiftで フレームワークを再設計しました フレームワークは初心者にも 使いやすいように設計しました 上級開発者向けの カスタマイズフックも提供しています 今年はフレームワークを強化し より簡単に医療アプリケーションを作成する 最新ツールの構築に尽力しました 古くて退屈なアジェンダを提供するのではなく 新しいCareKit機能用に ステッカーパックを作成しました ステッカーが嫌いな人はいませんよね? このセッションでは すべてのステッカーを集め MacBookにタックします まず CareKitUIからお話します CareKitUIはタスク チャート 連絡先を 可視化するための様々なビューを提供します 今年はフレームワークの新しいビューも 追加しています CareKitで構築された ウェルネスアプリケーションのコンテキストで 新しいビューを見てみましょう 私のフィードと関連する カードのリストが表示されています 各カードはフレームワークに追加した 新しいビューです 1つ目のSimpleTaskViewからは 日課のストレッチを思い出します 以前にCareKitで作業していれば このビューには慣れているでしょう SimpleTaskView用のUIKit APIは 既に用意されており SwiftUI APIも追加されています SwiftUI APIについて詳しく説明します 最初にCareKitUIとSwiftUIをインポートし ボイラープレートSwiftUIコードを書きます 次にSimpleTaskViewを 本文に追加します タスクが完了したかどうかを決定するタイトル 詳細 フラグでビューを初期化しました このビューを少しカスタマイズしてみましょう SwiftUIテキストを受け入れるタイトルと 詳細パラメータを詳しく見ていくと カスタムビュー修飾子で タイトルと詳細を装飾できます ヘッダーのハイライト表示を抑えるために タイトルは細いfontWeightにします どのように変更したのか ご注目ください
既定のfontWeightに戻り 利用可能な 別のカスタマイズポイントを確認します
SwiftUIを使用すると 複数の小さなビューコンポーネントを構築します それを1つの構成にまとめ より豊かで機能的なビューを作成できます シンプルタスクビューの構成には 複数の小さな ビューコンポーネントも使用しています 詳細開示とヘッダーがあります 必要に応じて 独自のカスタムヘッダー または詳細開示をビューに挿入するオプションを デフォルトの代わりとしてご利用いただけます このビューのカスタムヘッダーを 作成してみましょう
コードに戻り 利用可能な別の初期化子を使用します カスタムヘッダーを構築できる場合に クロージャを提供し CareKitUIが有用な 小さなビューコンポーネントを提供します HeaderViewを使用し 他のCareKitUIカードの スタイルに一致させます ヘッダーにタイトルと詳細を渡し HStackのカスタムアクセントバーの横に 配置します
これでビューはカスタムできたので 別のカスタマイズポイントを見てみましょう
カスタムビューを コンテンツの任意の側面にアタッチすると カードを任意の方向に拡張できます ビューの下部にコンテンツを添付するには いくつかのコードを見てみましょう
まずは 作業スペースを拡大するため 新しいビューを作成します 次に カードビューの内部で SimpleTaskViewをラップし 分割線と指示のテキストの横に配置します CardViewは CareKitUIの別のコンポーネントです あるカードを別のカードの内側にラップする時 一番外側のカードだけが表示されます これにより すべてのコンテンツを 1枚のカードにまとめることが可能です カスタムビューの構築が完了し 始めとは異なった外観になりました 最初はヘッダーと完了ボタンだけの シンプルなタスクビューでしたが 今はカスタムのアクセントバーと タスクの詳細指示が存在します ウェルネスアプリケーションに戻り CareKitUIの他の新しいビューを 見てみましょう
これはラベル付きの値ビューで 値および関連する単位を最適に表示します これは私の心拍数が 毎分62であることを示しています
前のビュー作成と同様に タイトルと詳細テキストを入力します 完了ステータスも入力します ビューをカスタマイズしたい場合は シンプルタスクビューで表示されたフックと 同じフックをビューに入力します
次にCareKitUIisに新しく追加するのは NumericProgressTaskViewです 目標に対する累積的な 進捗状況の表示に役立ちます 30分間の目標に対して 22分間運動したことが分かります 目標値に対するリマインダーです
ビューの作成には ヘッダーに表示する タイトルと詳細をもう1度渡します タスクの手順 進捗状況 目標に関するテキストも入力します 最後に タスクが完了したかどうかを 判定するフラグを渡します
次のビューはFeaturedContentViewです お気に入りの記事など大事な情報を ハイライト表示するのに最適です 自宅で調理可能な簡単で体に良いレシピを 紹介した記事があります
FeaturedContentViewの作成は 以前とは少し異なります 最初に CareKitUIとUIKitをインポートします 次にビューを定義し 背景に大きな画像 ビューの下部にテキストを設定します
FeaturedContentViewをタップすると 新しいDetailViewが表示されます DetailViewは画像の下のコンテンツ内のHTMLと CSSをサポートしており 事実上何でも置いておくことが可能です
ビューの作成は前回のビューと似ており 最初にCareKitUIとUIKitをインポートします 次に スタイル付きHTMLを定義します これはスタイルのHTMLと 関連CSSの組み合わせです
styledHTMLを渡すことで ビューをインスタンス化し 右上に閉じるボタンを表示するかどうかを 決定するフラグを指定します
最後に 画像を設定します
最後のビューはLinkViewです アプリケーションの内側または外側に 新しいビューを開くためのボタンを 最適に表示します これは理学療法士の予約の調整に 役立つリンクです
タイトル 説明 表示するリンクを指定して ビューを作成します アプリケーション内のウェブサイトを開くために 使用するリンクボタンを作成します これらのリンクオプションは Appleのオプションの一部にすぎません App Storeに移動するオプションもあります ユースケースに対応しない場合は カスタムURが利用できるオプションもあります アプリケーションの今日のフィードは 終わりに達したので フレームワークに追加する すべての新しいビューで終わります UIKitとSwiftUI APIの場合は 基本的にはロードマップを作成します 皆様には 新しいユースケースの 新しいビューを使用し― フレームワークを 改善していただきたいです CareKitUIビューの 最初のステッカーを受け取り WWステッカーのすぐ隣に付けます CareKitUIで静的ビューを 作成する方法をご紹介しました CareKitはさらに進化し 静的ビューを同期レイヤにラップします ストア内のデータが更新されると UIに変更が反映されます CareKitUIに新しいSwiftUIビューが 追加されたので CareKitに同期されたSwiftUIビューを 追加しています これらのビューの1つの 作成方法をご紹介します まず CareKit CareKitUI SwiftUIを インポートすることから始めます CareKitから単純なタスクビューを 作成するにはボディでtaskID eventQuery およびCareKitStoreへの参照を保持する SynchronizedStoreManagerを提供します ビューでは taskIDとeventQueryを使用し ストア内のタスクデータが検索されます ロケーションが分かれば ビューに自動的にマップされます SynchronizedStoreManagerは タスクデータが変更された時に ビューの更新を確認します タスクデータがビューにマップされる方法を カスタマイズしたほうがよいでしょう 別の初期化子を使用し 以前と同じパラメータを提供します CareKitUIから表示する基礎的なビューを 作成するクロージャも提供しています SwiftUIでこのビューのボディを再計算すると クロージャが呼び出されます
クロージャの内部では タスクデータとビューモデルへの参照を保持する コントローラへのアクセスが可能です ビューモデルは基礎となるビューの インスタンス化を支援する便利な構造体です ビューモデルを使用し CareKitUIのSimple TaskViewをインスタンス化してみましょう CareKitUIからビューを作成するので CareKitUIビューのカスタマイゼーション ポイントにアクセス可能となります ビューモデルの助けを借りて 既定のSimpleTaskViewを作成しました ビューに変更を加えてみましょう ビューをタップした時に ResearchKit アンケートを表示させるようにします
まず アンケートが表示されているかを 判定する状態プロパティを追加します 次に 表示されたタスクを researchKitSurveyTaskに変更します ビューをタップすると アクションが変更され isShowingSurveyフラグを trueに設定できます その旗がtrueの場合 ResearchKitSurveyで ポップオーバーを提示します CareKitカードでResearchKitSurveyを 提示している人が多いので ここをスタート地点とするとよいでしょう このセクションは終了したので 同期ビュー用の新しいステッカーを得て コレクションをさらに構築しましょう APIはSwiftUIを明示的に受け入れたので フレームワークに多くの利点をもたらしました それはシンプルなAPIと 多くのカスタマイズポイントです 最大の利点はSwiftUIでCareKitを Apple Watch向けに構築できることです watchOS向けにCareKit CareKitUI CareKitStoreのすべてを構築できます
現在 UI側ではシンプルなタスクビューと 指示タスクビューをサポートしていますが それぞれがApple Watch画面用に 微調整されています 皆様が新しいビューを進化させ Apple Watchの新しいビューを 構築されることを願っています
このセクションが終わったので 新しいWatchステッカーを付けます
次に アプリケーションの 正常性データ格納に最適な― CareKitStoreの更新プログラムを ご紹介します CareKitStoreは便利ですが デバイスのストアには 膨大な量の正常性データが保存されています そのストアとはHealthKitです HealthKitやCareKitデータで HealthKit駆動型タスクを作成します タスクはCareKitStoreに保存でき― HealthKitから生じるデータに基づいて 自動完了することが可能です 新しいHealthKitアーキテクチャを始める前に CareKitStoreの 現在のアーキテクチャを見てみましょう
OCKStoreはコアデータの実装になります ストア内のデータが変更時に通知を送信し― ビューを同期させるStoreManagerで ストアをラップします
StoreManagerを使用すると CareKitで同期ビューを作成できます HealthKit統合が画像に どのように適合するか見てみましょう
CareKitStoreストアの横に 新しい HealthKitパススルーストアを作成します CareKitStoreはコアデータを 真実の源として使用していますが HealthKitパススルーストアは HealthKitを真実の源として使用します
2つのストアを 新しいStoreCoordinatorでラップします StoreCoordinatorの操作は 個々のストア操作と同じです CareKitエンティティのメソッドの作成 更新 および削除を呼び出すします
StoreCoordinatorの内部ストアとの 通信方法を詳しく説明します
StoreCoordinatorに データのフェッチを依頼すると 内部ストアのリザルトが集計されます StoreCoordinatorに データの書き込みを依頼すると 1度に1つのストアにのみ 書き込みが行われます データの書き込みがトランザクション オペレーションであることが保証されます
新しいHealthKit統合を設定する コードをご紹介します まず CareKitとCareKitStoreを インポートします 次に CareKitStoreと HealthKitパススルーを作成し それぞれにアプリケーション固有の 名前を指定します
StoreCoordinatorを作成し 作成した2つのストアをアタッチします
最後に StoreCoordinatorで StoreManagerを作成します このStoreManagerで 同期されたCareKitビューの作成ができます
ストアを設定したら 追加するエクササイズタスクを作成しましょう
タスクが毎日午前8時に発生するように スケジュールを指定しました 30分間という運動時間の目標値も設定し 運動目標を表示するビューで使用します
次に HealthKitリンケージを作成すると タスクがHealthKit量にひもづけされます HealthKitデータ型に対応する 数量識別子 タイプ 単位を使用します
スケジュールと HealthKitリンケージが作成できたので 新しいタスクを作成し ストアに追加します
タスクを表示するには CareKitUIで導入した 新しいビューを使用します この場合 NumericProgressTaskViewは 進捗状況と目標値を示すため 完全に適合します 上のLabeledValueTaskViewは 特定の目標を持たないタスクが よりよい方法で表示されます
たくさんのステッカーを得ましたが HealthKit駆動型タスク用に スペースを設けましょう
ヘルスケア業界には HealthKit以外にも 多くのストレージシステムがあります その多くはFHIRと呼ばれる形式で データを格納します FHIRは簡単にデータを交換し 解析することができます アプリケーションでのデータベース操作を 簡単にするためFHIR互換性を導入しています
FHIRをさらに理解するために FHIR形式で構成された JSONのスニペットを見てみましょう
JSONはタイレノールの 投薬オーダーのデータで― FHIRの特定のリリースで形成されています CareKitはDSTU2やR4を含む いくつかのリリースで互換性をサポートします
FHIR互換性を有効にするため CareKitエンティティとFHIRデータの間で マッピング可能なコーダーを導入しています このマッピングを実現するために FHIRModelsと呼ばれる新しいオープンソースの Appleフレームワークを利用しています フレームワークの詳細はWWセッションの― “Handling FHIR Without Getting Burned”を ご参照ください FHIRデータを CareKitエンティティにマッピングする場合 多くは単一のFHIRリソースマップを 単一のCareKitエンティティにマップします FHIR患者がよい例でしょう FHIRリソースがCareKitエンティティよりも 細かい場合は FHIRリソースが 単一のCareKitエンティティに マッピングされる可能性があります ご自身でマッピングを行う場合は 考慮する必要があります
コーダーを高いレベルで理解できましたので 実際に作成します CareKitStoreと CareKitFHIRのインポートから始めます これはコーダーを含む 新しいSPMパッケージです
データのマッピングに責任を負う コーダーを初期化します R4リリースのJSONをCareKitエンティティに マッピングするコーダーを利用し―
CareKit患者を取り FHIRデータに変換します
逆方向にFHIRデータを取り出し CareKit患者に対してマッピングします プロセスでは最初に FHIRリソースデータを作成してください これにより バイナリデータが R4形式のJSONであることを保証し 安全にR4コーダーに渡すことができます FHIRデータとCareKitエンティティ間の マッピングは常に完璧ではありません 例えば CareKitエンティティのプロパティが FHIRリソースでは 完全に表現されないことがあります データ変換の際に誤変換されないように マッピングを自分で定義することが重要です ここでは 患者の名前をFHIRデータに マッピングする方法を定義できます このクロージャでは FHIRModelの フレームワークから名前と患者を受け取ります 実際に患者に その名前をマッピングする必要があります
逆に FHIRデータから 患者名をマッピングする方法を定義します FHIRModelのフレームワークから 患者を受け取りましたが 今回の仕事はCareKitエンティティの 名前コンポーネントを抽出することです これらのクロージャがFHIRModelsから型を 公開していることに注意してください 前述のように フレームワークは完全にオープンソースであり すべてのソースコードをCareKit GitHubページで 見つけることができます
FHIRの更新の説明は以上です 新しいステッカーを付けましょう 素晴らしい
次はエリックが CareKitStoreの アップデートについて説明します エリック よろしく ありがとう ガヴィ 皆さん こんにちは エリックです 私もCareKitチームのエンジニアです CareKitの素晴らしい新機能をご紹介し デモを行いたいと思います ガヴィはCareKitが ストア内のデータとビューの同期を維持するのに どう役立つかについて説明しました 私がご紹介するのは異なる種類の同期 つまり サーバーでの同期です CareKitがオープンソースになってから CareKitアプリケーション内のデータを サーバーと同期させる方法についての 問い合わせが多く寄せられました
私たちは効率的に 同期させる方法を検討しました 本日は新しいCareKitリモート同期APIを ご紹介します 新しいリモート同期APIによる CareKitと通信するためのプロトコルの定義です これらの規則を監視するサーバーは CareKitアプリケーションの 同期バックエンドとして使用されます
CareKitアプリケーションを使用して リモート同期を有効化すれば タスクを完了したローカルで変更が行われ リモートサーバーに同期されます
他のデバイスでも サーバー上のデータを操作できます その場合 他のデバイスで ユーザの新しいタスクが追加されます 続いて患者情報がサーバーと同期され 更新を受け取ったストアは その内容を表示します こうした操作を可能にするのは 新しいAPIの2つの要素です 1つ目はiOS開発者向けの OCKStoreの拡張機能に関連するもの 2つ目はサーバーにCareKitのサポートを 追加する新しいプロトコルです アプリケーション開発の側面から 見ていきましょう
OCKStoreの初期化子に 新しいリモートパラメータを追加しました このパラメータに引数を渡すと CareKitは指定したオブジェクトとの リモート同期を有効にします 遠隔nilを離れるとCareKitは 以前と同様に完全なオフラインで機能します
新たに追加した同期メソッドを呼び出すと その名のとおりローカルストアと リモートストアの同期が促されます ポリシーパラメータのデフォルト値は 通常 任意の値になります しかし パートナーのデータを使用して ローカルかリモートのデータを 完全にオーバーライトすることも可能です
実際の使用例をご紹介しましょう まずCareKitStoreとVendorSDKを インポートします 内容は後で説明しますが 一旦パッケージがあると仮定しましょう
次にOCKRemoteSynchronizableに 準拠するクラスをインスタンス化します OCKStoreの初期化子にインスタンスを渡し 普段どおりにストアを使用します 多くのリモートで自動同期が サポートされているため CareKitは必要に応じて 同期メソッドを呼び出します
もちろん好きな時に 手動で同期を開始することも可能です ここまではアプリケーション開発の 側面を見てきました もう1つの側面は新たな OCKRemoteSynchronizableプロトコルです バックエンドエンジニアや クラウドプロバイダーが CareKitのサポートを サーバーに追加する時に使用します このプロトコルには5つの条件があります
ユーザはクラスにデリゲートを実装し CareKitに影響するサーバーで 変更が生じた場合には警告する必要があります
自動同期の要否についてもCareKitに通知します 確定的な単体テストの場合は オフにすると便利ですが 通常はtrueに設定しておきます
サーバーからの変更をフェッチする メソッドの入力も必要です ベクトルクロックとして知られる knowledgeVectorをCareKitから受け取ります これは特殊なデータ構造をしており サーバー側でデバイス上のデータを 正確に把握することが可能です ユーザはサーバーに このベクトルを送信し リビジョンレコードと交換します そのリビジョンレコードを マージビジョンのクロージャに渡し 完了したら完了ブロックを呼び出し表示します
次の条件はpushRevisionです 前回のチェックイン以降 デバイス上で発生したすべての変更は デバイスリビジョンとして提供されています ユーザはこのリビジョンレコードを サーバーに渡し 完了後に完了クロージャを呼び出して CareKitに通知します
競合する変更が デバイスとサーバーで行われる場合には chooseConflictResolutionPolicyが 呼び出されます 競合するエンティティ両方のバージョンの コピーが表示されるため 内容を精査し どちらを保持するかを決めます
このプロトコルとサーバー側のロジックを 実装することにより CareKitとの新たな統合を作成できます 現在 Appleでは 特注サーバーの実装は提供していませんが 他で簡単に実装できるようにしました あるパートナーが既に製品化しているのです IBM Cloud Hyper Protect Servicesの中で IBM社はCareKitのサポートを初めて追加しました しかもそれをGitHubにあるCareKitの オープンソースコミュニティで提供しています SDKの詳細はIBM社の セルフガイドラボでご確認ください ここまでたくさんお話しました この後のデモが楽しみです 先ほど ご紹介した新しい同期APIを使用し その知能の高さをお伝えましょう リモート同期APIの主な目的はサーバーと iOS CareKitアプリケーションの同期です しかし ここでは同じAPIを使用して iOSアプリケーションと相棒である watchOSアプリケーション間で データを同期する方法をご紹介します 本日作成するアプリケーションは ユーザーに毎日のストレッチを通知し 筋肉のけいれんを計測して その2つの相関関係をチャートで表します 私たちの目標は 両方のデバイスで同じタスクが表示され 一方で完了されたら 自動でもう一方も更新されるようになること
現在のiOSアプリケーションは 昨年のセッションで作成したサンプルアプリ ケーションのプルーンダウン版にすぎません
まだその動画をご覧でなければ ぜひ今日に至るまでの過程をご確認ください ではXcodeを始めましょう 先ほどご説明したように iOSアプリケーションは完成しているので 最高のwatchOSを作成することに注力できます まずApple Watchアプリケーションと iOSアプリケーションの同期を設定しましょう 新しいクラスである OCKWatchConnectivityPeerを活用します このクラスはリモート同期可能なプロトコルに 準拠するため Apple WatchとiPhoneは 互いのリモートストアとして機能します インスタンス化する際 このリモートはストアに渡します
本日はWatchConnectivityでの作業を行います WatchConnectivityを使用すると iOSとwatchOSの間で送受信されるメッセージは すべてセッションデリゲートから流し込まれます これは通常アプリケーション開発者である あなたが管理するクラスです つまりCareKitが そのメッセージを送受信するには あなたの協力が必要なんです 具体的にご説明しましょう
WatchConnectivityセッションを セットアップしアクティブ化します デリゲートを設定し activateメソッドを呼び出します
続いてデリゲートとして機能する 小さなヘルパークラスを定義 WatchConnectivityセッションデリゲートには 2つの必須メソッドがあります 1つ目はActivationDidComplete 最初の同期に最適な場所と言えそうです
2つ目のdidReceiveMessageは iPhoneからのメッセージが Apple Watchに着信するたびにトリガーされます ここでCareKitをサポートします
メッセージを受け取るたびに CareKitリモートに表示し 応答するチャンスを与えましょう
その後 応答を取りCareKitの代わりに iPhoneに転送します
あとは新しいクラスのインスタンスを 作成するだけです セッションデリゲートとして 設定することをお忘れなく
通常はiOS側でも同じ設定を 実行する必要があります ただ 全く同じ設定なので 前もって いくつか事前デモを実施しました watchOSにリモートセットアップをし iOSも同様にセットアップしました 同期の準備は完成しています 続いてビューに取りかかります
ストア内の最新データを使い ビューを最新に保つには SynchronizedStoreManagerへの 参照付きビューの提供が必要です ここで作成しましょう
SwiftUIにビューを構築します SwiftUIを使用し ビューにStoreManagerへの参照を提供する場合は EnvironmentValuesが非常に有効です
ここでSynchronizedStoreManagerを提供する 新しいEnvironmentKeyを定義しています デフォルト値はextensionDelegateが所有する インスタンスを使用します
TodaysTasksViewを拡張し 新たなプロパティ“storeManager”を定義
そのプロパティはTodaysTasksView内の 変数としても使います
storeManagerへの参照ができたので ビューを具体化しましょう 2枚のタスクカードを表示したいので ScrollViewの内部で両方をラップします 続いてScrollViewを赤色にし iOSアプリケーションのテーマに合わせます
iOSではInstructionsTaskViewを使うため ここでは全く同じ作業を行います
同様に けいれんカードには SimpleTaskViewを使用
レポート機能についての説明は省略し 二次初期化子の使い方を実演しましょう 詳細ラベルを非表示にし 鮮明なビューを作成するのが目的です
ビューが構築できたら アプリケーションは完成です ビルドして実行したものが どう見えるか確認しましょう
アプリケーションを初めて実行する時は― タスクはApple Watch上にすぐ表示されません watchOSとiOSの間で同期が完了するまでに 少し時間がかかるからです
しかし 一度実行すると 表示されるようになります やってみましょう iPhoneで作成した筋肉の測定レポートは Apple Watchでも表示されるでしょうか うまくいきました CareKitのすべてのビューは ストアと同期されます つまりApple Watchで ストレッチタスクを確認すると一瞬で― iPhoneの更新と同時にサブスクライブされた 全ビューが表示されるのです 服薬管理表 ストレッチタスクカード そしてチャートにご注目ください タスクを完了中です
何だかとても満足感を得られます
他にもできることはありますが 要点は理解できたと思います この辺りでデモを終了しましょう おさらいです
本日はCareKitの新しいAPIをご紹介しました 既存のサーバーやクラウドへ そのサポートを追加する方法もお伝えしました さらに このAPIを使用してApple Watchを iPhoneと同期する方法を実演しました
このAPIに全力を注いできたので リモート同期ステッカーを要求しましょう
ここからは再びガヴィが 最終トピックである コミュニティの更新についてお話しします ガヴィ よろしく ありがとう エリック 新しいリモート同期APIが リリースできて嬉しいです 皆さんのアプリケーションでの 活用方法が楽しみです このあとはコミュニティの更新について 詳しくご説明します コミュニティでは毎年 すばらしい仕事がなされていて 本日は皆さんとその最新情報を 共有したいと思います
先ほどエリックが 新しい同期APIをご紹介しました そしてIBM社は APIの最初の採用企業となりました CareKit GitHubページでは 全ソースコードをご覧いただけます
セッションではリモート同期とは別に― 毎年CareKitやResearchKitが活用された 優れたアプリケーションを取り上げています OYMアスリートアプリケーションはチャート ビューで日々の食事やその傾向を分析し アスリートの栄養管理を支援します HEALTHConnectedアプリケーションは 医師や家族と健康データを共有したり 連絡先やチャートを活用するのに役立ちます
COVID-19への対応でCareKitや ResearchKitが活用されている例もあります スタンフォード大学のアプリケーションは 初期対応者が自身のリスクを評価し 検査を受けられるよう支援します ネブラスカ大学のアプリケーションは 感染症の詳しい調査に役立てられています
すべて今年リリースされた アプリケーションですが フレームワークがどう活用されているのか 少しご紹介しましょう
昨年リリースを発表した新ウェブサイトは 現在 researchandcare.orgの ランディングページとなっています 概要ページでCareKitとResearchKitの機能が 紹介されています フレームワークの活用方法について ヒントを得られるでしょう
CareKitの具体的な情報を得るには サイト上部のCareKitタブを開いてください スクロールすると さまざまな健康支援プログラムでの 活用事例をお読みいただけます
Apple Watchを使用した研究を対象とした 支援プログラムも紹介されています プログラムにご興味がある方は このページのメールアドレスへご連絡を
アプリケーションでResearchKitとCareKitを 使用している人は大勢います フレームワークの活用事例と その方法をぜひお聞かせください こちらの送信フォームからご連絡を
さあ コミュニティの更新について ステッカーを受け取る時間です 新しいUIからCareKitStoreの機能強化まで あらゆることをご紹介しました すべてのアップデートを 楽しみにしていただければと思います そろそろCareKitの新バッジを受け取りましょう
フレームワークの構築の際はGitHubのページと 新しいウェブサイトをご覧ください
ご存知のようにCareKitは オープンソースのフレームワークであり コミュニティに参加している 皆さんの協力を得て進化してきました ですから ためらわずに GitHubで質問してみてください 最後にチームから一言お礼を言わせてください 当フレームワークの支援者や 世界中で健康改善を促進している方々へ 皆さんが次に何を作り出すのか とても楽しみです
-
-
2:23 - Simple Task View
import CareKitUI import SwiftUI struct MySimpleTaskView: View { var body: some View { SimpleTaskView( title: Text("Stretches"), detail: Text("15 minutes"), isComplete: false) } }
-
2:52 - Simple Task View - View Modifiers
import CareKitUI import SwiftUI struct MySimpleTaskView: View { var body: some View { SimpleTaskView( title: Text("Stretches").fontWeight(.thin), detail: Text("15 minutes"), isComplete: false) } }
-
3:42 - Simple Task View - Custom Header
struct MySimpleTaskView: View { var body: some View { SimpleTaskView(isComplete: false) { HStack { RoundedRectangle(cornerRadius: 5) .fill(Color.accentColor) .frame(width: 5) HeaderView( title: Text("Stretches"), detail: Text("15 minutes")) } .padding() } } }
-
4:29 - Simple Task View - Appending Views
import CareKitUI import SwiftUI struct MyComposedSimpleTaskView: View { var body: some View { CardView { VStack(alignment: .leading) { MySimpleTaskView() Divider() Text("...") .font(.caption) .foregroundColor(.secondary) }.padding() } } }
-
5:24 - Labeled Value Task View
import CareKitUI import SwiftUI struct MyLabeledValueTaskView: View { var body: some View { LabeledValueTaskView( title: Text("Heart Rate"), detail: Text("Most recent measurement") state: .complete( Text("62"), Text("BPM") )) } }
-
5:57 - Numeric Progress Task View
import CareKitUI import SwiftUI struct MyNumericProgressView: View { var body: some View { NumericProgressTaskView( title: Text("Exercise Minutes"), detail: Text("Anytime"), instructions: Text("..."), progress: Text("22"), goal: Text("30"), isComplete: false) } }
-
6:28 - Featured Content View
import CareKitUI import UIKit let featureView = OCKFeaturedContentView() featureView.imageView.image = UIImage(named: "groceries") featureView.label.text = "Easy & Healthy Recipes"
-
6:58 - Detail View
import CareKitUI import UIKit let styledHTML = OCKDetailView.StyledHTML( html: html, css: css) let detailView = OCKDetailView( html: styledHTML, showsCloseButton: true) detailView.imageView.image = UIImage(named: "groceries")
-
7:41 - Link View
import CareKitUI import SwiftUI struct MyLinkView: View { var body: some View { LinkView( title: Text("Physical Therapist Appointment"), instructions: Text("..."), links: [ // ... .website( "https://www.apple.com", title: "Website") // ... ]) } }
-
8:56 - Synchronized Task View 1
// Synchronized Task View import CareKit import CareKitUI import SwiftUI struct MySynchronizedTaskView: View { let storeManager: OCKSynchronizedStoreManager var body: some View { CareKit.SimpleTaskView( taskID: "stretch", eventQuery: OCKEventQuery(for: Date()), storeManager: storeManager) } }
-
9:26 - Synchronized Task View 2
@State private var isShowingSurvey = false var body: some View { CareKit.SimpleTaskView( taskID: "researchKitSurveyTask", eventQuery: OCKEventQuery(for: Date()), storeManager: storeManager) { controller in CareKitUI.SimpleTaskView( title: Text(controller.viewModel?.title ?? ""), detail: controller.viewModel?.detail.map(Text.init), isComplete: controller.viewModel?.isComplete ?? false) { isShowingSurvey = true } } .popover(isPresented: $isShowingSurvey) { ResearchKitSurvey() } }
-
13:43 - Setting up the store
// Setting up the Store import CareKit import CareKitStore let coreDataStore = OCKStore(name: "core-data-store") let healthKitPassthroughStore = OCKHealthKitPassthroughStore(name: "hk-passthrough—store") let coordinator = OCKStoreCoordinator() coordinator.attach(store: coreDataStore) coordinator.attach(eventStore: healthKitPassthroughStore) let storeManager = OCKSynchronizedStoreManager(wrapping: coordinator)
-
14:15 - Adding HealthKit linked tasks to the store
// Adding HealthKit Linked Tasks to the Store let schedule = OCKSchedule.dailyAtTime( hour: 8, minutes: 0, start: Date(), end: nil, text: nil, duration: .allDay, targetValues: [OCKOutcomeValue(30.0, units: "Minutes")]) let link = OCKHealthKitLinkage( quantityIdentifier: .appleExerciseTime, quantityType: .cumulative, unit: .minute()) let steps = OCKHealthKitTask( id: "exerciseMinutes", title: "Exercise Minutes", carePlanUUID: nil, schedule: schedule, healthKitLinkage: link) storeManager.store.addAnyTask(steps)
-
16:57 - Encoding and decoding FHIR data
// Encoding and Decoding FHIR Data import CareKitStore import CareKitFHIR let coder = OCKR4PatientCoder() // CareKit entity to FHIR data let patient = OCKPatient(...) let json = try! coder.encode(patient) // FHIR data to CareKit entity let data: Data = //... let resourceData = OCKFHIRResourceData<R4, JSON>(data: data) let patient: OCKPatient = try! coder.decode(resourceData)
-
17:49 - Customizing the data mapping 1
// Customizing the Data Mapping // Encoding process coder.setFHIRName = { name, fhirPatient in // ModelsR4.Patient let humanName = HumanName() humanName.family = name.familyName.map { FHIRPrimitive(FHIRString($0)) } humanName.given = name.givenName.map { [FHIRPrimitive(FHIRString($0))] } fhirPatient.name = [humanName] }
-
18:10 - Customizing the data mapping 2
// Customizing the Data Mapping // Encoding process coder.setFHIRName = { name, fhirPatient in // ModelsR4.Patient let humanName = HumanName() humanName.family = name.familyName.map { FHIRPrimitive(FHIRString($0)) } humanName.given = name.givenName.map { [FHIRPrimitive(FHIRString($0))] } fhirPatient.name = [humanName] }
-
25:56 - Creating the remote
private lazy var remote = OCKWatchConnectivityPeer()
-
26:09 - Setting up the remote store
private lazy var store = OCKStore(name: "sample-store", remote: remote)
-
26:18 - import WatchConnectivity
import WatchConnectivity
-
26:33 - Setting up the Watch Connectivity Session
WCSession.default.delegate = sessionDelegate WCSession.default.activate()
-
26:53 - Stub out session delegate class
class SessionDelegate: NSObject, WCSessionDelegate { let remote: OCKWatchConnectivityPeer let store: OCKStore init(remote: OCKWatchConnectivityPeer, store: OCKStore) { self.remote = remote self.store = store } func session( _ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) { print("New session state: \(activationState)") } func session( _ session: WCSession, didReceiveMessage message: [String: Any], replyHandler: @escaping ([String: Any]) -> Void) { print("Received message from peer!") } }
-
27:02 - Kick off first synchronization
if activationState == .activated { store.synchronize { error in print(error?.localizedDescription ?? "Successful sync!") } }
-
27:11 - Forwarding replies on CareKit's behalf
remote.reply(to: message, store: store) { reply in print("Sending reply to peer!") replyHandler(reply) }
-
27:39 - Creating the delegate
private lazy var sessionDelegate = SessionDelegate(remote: remote, store: store)
-
28:10 - Setting up the synchronized store manager
private(set) lazy var storeManager = OCKSynchronizedStoreManager(wrapping: store)
-
28:27 - Defining a new environment key
private struct StoreManagerKey: EnvironmentKey { static var defaultValue: OCKSynchronizedStoreManager { let extensionDelegate = WKExtension.shared().delegate as! ExtensionDelegate return extensionDelegate.storeManager } }
-
28:51 - Defining a store manager environment value
extension EnvironmentValues { var storeManager: OCKSynchronizedStoreManager { get { self[StoreManagerKey.self] } set { self[StoreManagerKey.self] = newValue } } }
-
28:57 - Adding an environment variable to the view
@Environment(\.storeManager) private var storeManager
-
29:04 - Setting up the scroll view
ScrollView { }.accentColor(Color(#colorLiteral(red: 0.9960784314, green: 0.3725490196, blue: 0.368627451, alpha: 1)))
-
29:22 - Displaying the stretch task card
InstructionsTaskView( taskID: "stretch", eventQuery: OCKEventQuery(for: Date()), storeManager: storeManager)
-
29:33 - Displaying the muscle cramps task card
SimpleTaskView( taskID: "cramps", eventQuery: OCKEventQuery(for: Date()), storeManager: storeManager) { controller in .init(title: Text(controller.viewModel?.title ?? ""), detail: nil, isComplete: controller.viewModel?.isComplete ?? false, action: controller.viewModel?.action ?? {}) }
-
-
特定のトピックをお探しの場合は、上にトピックを入力すると、関連するトピックにすばやく移動できます。
クエリの送信中にエラーが発生しました。インターネット接続を確認して、もう一度お試しください。