ドイツのCOVID-19のシステムがすごいなって

ドイツのCOVID-19対策アプリのコードを検索したら、ガチだなって思ったので、ポエムを書きます。

ランディングページは https://coronawarn.app です。このアプリを使うことで得られるメリット、陽性判定時の登録や曝露通知の受け取りなどの使用フロー、プライバシーの保護、そしてオープンソースで運営していることが説明されています。20日時点で1000万ダウンロードを超えるようです。

開発の事業者

ホームページ、登録/検証サーバ及びiOSとAndroidのネイティブアプリなど、このシステム一式が https://github.com/corona-warn-app にあります。それぞれのライセンスを見ると、ライセンス形式はどれも Apache License, Version 2.0 です。著作権者は、ベリフィケーション・サーバーが Deutsche Telekom AG.、ウェブサイトが Deutsche Telekom AG and SAP SE or an SAP affiliate company.、サーバー及びモバイルアプリがSAP SE or an SAP affiliate company.となっています。主軸の開発はSAPで、後に出てくる認証サーバーはドイツテレコムが構築するチーム構成のようです。

システム構成

ドキュメントのなかに、全体アーキテクチャが説明されています https://github.com/corona-warn-app/cwa-documentation/blob/master/solution_architecture.md 。図を見ているだけで、ものすごくわかった気持ちになるドキュメントです。図はSAPが内部で使う FMC と UML を融合させたTAM http://www.fmc-modeling.org/fmc-and-tam という形式だそうです。なんとなく眺めてみます。

コンポーネンツ

登場人物は、利用者と、厚生省庁そして検査機関と医師の3つです。サーバーはオープンテレコムクラウドでホストされます。

ベリフィケーションのインタラクションフロー

左上から、利用者のアプリインストールと通知を受け取るためのサインアップ(オプショナル)、感染検査とその結果の受け取り、アプリの感染者のテンポラリキーの回収が書かれています。teleTANは、人が読むことができるトークン文字列です。

ベリフィケーションのデータフロー

ベリフィケーションのデータフローは、数字の順番に見ていくと、処理の流れがわかります。アプリとサーバー間で、GUIDや登録トークンを交換し、それらはハッシュ関数に通して保存されます。テスト結果サーバー/確認サーバー/テンポラリキー保存サーバがそれぞれあり、サーバーの中核になるのが確認サーバーです。

このドキュメントから、それぞれのサーバー及びアプリの開発に、チームごとに開発が下りていくのでしょうが、それぞれの関係が纏まっていて、わかりやすいです。また、Apple/Googleの曝露通知の仕組みを、識別子やBLEの振る舞いまで細かく説明をしていて、プライバシー保護などの根拠として十分な技術情報がまとめられています。よくできてます。

陽性判定者と接触したことを通知するときに、オプションで、その通知者のテンポラリキーも回収する作りになっていたりと、とにかく感染の可能性のある人を見つけようとする仕組みが細かいところに入ってる感じで、よく練られてるんだろうなと感じます。

iOSアプリ

欧米ではAndroidのシェアが大きくiPhoneは少数派ですが、私がiOSしか分からないので、iOSのコードを見てみます。 https://github.com/corona-warn-app/cwa-app-ios

アプリ画面

アプリ画面のデザインは、今時の全画面で有機ELなiPhoneらしい、白を基調として、アイコン的な画像と十分に大きな文字で説明、そして最後に確認ボタンを配置した、現代的なアプリデザインです。みやすいです。

コードを開くと、UIはパーツごとにxibファイルに分割されていて、チーム開発でコンフリクトが生じにくいよう範囲が最小になっています。シンプルなアプリのはずですけど、ものすごいファイル数です。

/post/deutsche-covid19-app/1.jpg

当然と言えば当然なのですが、UIテストなどのターゲットが作られていて、リリースサイクルも管理されていて、いい感じです。

wwdc2020 キーノートまとめ

キーノートを自分なりにまとめます

https://developer.apple.com/wwdc20/ から、WWDC2020のキーノートの要点と着目点を列挙していきます。キーノートの概要は、各ネットニュースで掲載されていますから、ここは自分の着目点とその理由を書いていきます。

COVID-19対策のため、プレゼンテーション会場に参加者がいない初めてのWWDCとなりました。WWDCのキーノートは全体に落ち着いたプレゼンテーションです。iOS登場時のような、熱狂的な雰囲気はありません。ですが、今年のキーノートは、ここ6年ほどのiOSデバイスの発展の歴史を、一度整理して、利用者の視点からシームレスで、使いたい機能を探さなくても、使いたい機能がすっと使える自然さにまとめ上げていく、次の10年を予感させる内容でした。

Apple Silicon

Apple製品全体のプロセッサを自社開発品に切り替えていく、Apple Siliconが発表されました。これまでIntelのプロセッサを使用し続けてきたMacも、iPhoneがそうであるように、Apple自社設計チップに切り替わっていきます。2年ほどを移行期間として、当面はインテルプロセッサ搭載Mac製品も出るようです。

Mac向けには、デスクトップにふさわしい消費電力と処理能力のバランスをとった新チップを設計するようです。AMD Ryzenを採用したMacが登場する可能性は、これでなくなりました。Macの中身がどうなろうが、MacがMacであることには違いがありません。利用者にとって、目に見える当面のメリットは何もないでしょう。

iPhoneのプロセッサの内部を見ると、演算処理をするプロセッサ部分は存外大きくはなく、その面積は、グラフィックのGPU、機械学習のニューラルチップ、外部と高速な情報のやり取りをするインタフェース、セキュリティ専用コア、そしてキャッシュメモリと、高速に情報をやり取りする構成要素の詰め合わせです。Apple Siliconが、ノートパソコン/デスクトップ/ハイエンドデスクトップに、どの製品から、どのようなチップを提供するのかは、興味があるところです。TSMCの7nm及び5nm、ローパワーライブラリ/ハイパフォーマンスライブラリで、ノートとデスクトップの製品分野でシングルスレッドの性能の違いを出すでしょうか。あるいはノートとデスクトップで、それぞれのローエンドとハイエンドで、性能の異なるチップを採用する、価格帯横串で違いを作るでしょうか。AMDのようにチップレットのパッケージ内高密度実装をベースに、必要な性能だけチップレットを増やす構成でしょうか、あるいはGPGPUのチップ間超高速接続のような仕組みで、パッケージを増やして全体処理能力を上げるのでしょうか。

Apple Siliconの登場で、開発者は、再ビルドでApple Silicon対応のバイナリを配布する必要があります。x86エミュレーション(ロゼッタストーン2)/iPadアプリをビルドでmacOSに移植もあります。また、Adobeのグラフィックソフトウェア、MS社のオフィスツール、Unityなど、開発やオフィスツールのネイティブ対応での協業が発表されていますから、ツールとしての問題はないでしょう。

パーソナルコンピュータ市場全体でのMacのシェアは7%程度のようです。iOSアプリなどの開発ツールを使う場合はMac以外のパーソナルコンピュータを選ぶことはありませんが、一般業務では、Macはいくつかある選択肢の1つです。iOSデバイスとのシームレスな機能などを利便性と感じて選ぶか、あるいは、もしも消費電力が小さければ、二酸化炭素排出量削減への貢献から企業として調達リストに入れるか、業務利用するMacの設定などの管理ソフトで管理費用などを考慮するかなど、いくつかの視点で選べばいいでしょう。

iOS14

豊富なiOSアプリケーションが、アプリストアに溢れています。この豊かさは、アプリ販売やアプリ内課金で収益が上げられるからです。開発者の新たなiOSへの機能の関心は、単純に新技術への好奇心に加えて、これらの収益が得られるか、収益をより大きくできるか、また新たな収益の場面が登場するかと、収益が関心の中心にあります。

iOS14では、アプリ拡張からウィジェットとAppClipsが作れるようになります。

ウィジェットは、iOS14以前からありましたが、ホーム画面に常駐できるようになります。ウィジェットの常時稼働は消費電力とメモリを消費しますが、ウィジェットのUIをシリアライズしてホーム画面アプリに渡し、ホーム画面アプリは非同期でそれを表示反映する仕組みにより、ウィジェットアプリが常に動作しなくてもよい仕組みを取り込んでいます。ちょうど、初代WatchOSが、Watch単体でアプリが実行できず、iPhoneでアプリ拡張が生成した画面イメージをWatchに転送することで、Watchでアプリが動いているかのように見せていましたが、あの仕組みを思い出させます。

AppClipsは、アプリストアからアプリをダウンロードしなくても、小さなアプリ拡張をその場で実行表示する仕組みです。Androidにある、Instant appsと同じでしょうか? 10MB以下とサイズが制約されています。例えば、買い物で1回しか使わない場合など、AppClipsで支払い画面を出し、そこで支払いを完了してもいいでしょう。継続して使うなら、アプリ本体をストアからインストールすればいいのです。AppClipsを簡単に見つけられるように、円形のバッジのような独特のQRコードのようなマーク、App Clipコード、も提供されます。

アプリをインストールしてもらう壁は、思うよりも高いものです。展示会向けにカタログ代わりのアプリケーションを提供する場合は、インストールに至る工夫が不可欠です。今は、カメラアプリがQRコードに対応しているので、ポスターにアプリストアへのリンク情報を含むQRコードを印刷してインストールを促進できます。App Clipsの優位性は、支払い処理がワンクリック、アカウント認証が組み込みやすいことで、リアル世界でのお金のやり取りが伴う、ちょっとした場面に最適に思えます。

オフライン動作する、音声とテキストの通訳ソフトが入ります。翻訳デバイスの市場を破壊してしまいそうです。

Mapは、自転車用と電気自動車用の経路検索が追加されます。電気自動車の充電スポットが表示されるなど、用途に合わせた経路上の情報が提示されます。利用可能としが、NYなど米国の都市と北京など中国の都市で、Appleにとっての中国市場の重要性が現れていました。

現行のiPhoneには、UWBでセンチメートル単位で距離がわかるU1チップが採用されていますが、これを使いiPhoneが車の鍵になります。BMWなどから、今年後半また来年にかけて対応車が登場します。午後に子供に車の利用を許す場合には、メッセンジャー経由で子供のiPhoneに許可データを送れば、子供のiPhoneでロック解除できるなど、ソフトウェア的な鍵の体験になっています。

FindMy Networkに、3rdのアクセサリがアクセスできる。3rdのApple関連機器に、FindMy Networkが解放。デバイスがどこにあるのか、iPhoneデバイスと統合されて表示される。これ、リアルデバイスのAppleへの紐付けですね。https://developer.apple.com/find-my/

HomeKitも、それ自体がオープンソース化、さらにAmazonのアレクサ対応機器など数多くのスマートホームのプラットホームとの連携、今まで対応機器が広まらない1ブランドだったのに、iPhone利用者にはユーザの接点としての統合窓口HomeKitみたいな橋頭堡を得た感じしますね。

iPadOS

検索窓に手書きで書き込むと、それがテキストデータになって入力される場面がありました。検索窓には、テキストを入力する細長いエリアがありますが、そのエリアを超えて手書き文字が書かれているのに、そのエリアに認識結果のテキストが入ります。

UIKitを使ったことがあるなら、UIの入力イベントはUIViewの矩形領域内部に限られるのを思い出すかもしれません。ですが手書きできる領域が、あの小さなテキスト入力領域だと、ものすごく不便です。その辺りにはそのテキスト入力エリアしかないのですから、その辺りに手書きすれば、そこにテキストが入るのが自然です。これをUIKitの考え方で実装するのは、ちょっとややこしく、だから手書き入力パッドを画面の別の場所に表示させて、そこで認識させたテキストが反映される、キーボード入力のペン代替みたいな、実現できる実装をします。そういう逃げをしないところが、いい感じです。

SwiftUI

AppClips、WatchOS、iOS、iPadOS、macOSと、いくつもの画面サイズにシームレスに対応していく必要が出てきます。SwiftとSwiftUIを使い始めるタイミングなのでしょう。もう、AutoLayoutでどうにかできる話では、ないようです。

日本独自のCOVID-19に対する曝露通知アプリケーションのソースコードを読んでみる

日本独自のCOVID-19に対する曝露通知のiOSアプリケーションのソースコードが、いろいろ勉強になると思ったので、読んでみるメモです。 レポジトリ: https://github.com/mamori-i-japan/mamori-i-japan-ios

ポイント:

フォルダ配置

Xcodeのフォルダ配置は、アプリケーションのトップの下にリソースとソースコードがあり、それぞれその下に細分化したフォルダが並びます。

  • Resources
    • Config
  • Sources
    • Models
    • Navigations
    • Networks
    • Screens
    • Services
    • Utilities
    • Views

Sourcesの下には、データモデル、画面遷移のナビゲーション、ネットワーク関連、UIViewControlに相当するScreens、ネットワークアクセスなどの機能の窓口となるサービス、ユーティリティ、Viewがが並びます。よくあるグループの分け方で、わかりやすいです。

ライブラリのライセンスの自動生成

アプリケーションで使用しているライブラリのライセンスを、設定画面に一覧表示する部分を、自動生成しています。

iOSの"設定"アプリに、それぞれのアプリケーションごとに通知などの設定画面があります。Settings.buldleで、その画面にアプリケーション独自の項目を追加できます。Settings.bundle, https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/UserDefaults/Preferences/Preferences.html

自動生成に、A license list generator of all your dependencies for iOS applications, https://github.com/mono0926/LicensePlist を使っています。ビルド時にシェルスクリプトを動かして、Settings.bundle以下に、ソフトウェアラインセスの一覧を追加します。

デバッグと本番の設定分け

/post/ios-code-reading-mamoriai/2.png

Firebaseの設定など、デバッグと本番とで必ず設定が異なる部分は、xcconfigを使っています。ちょっとした差分設定で、かつXcodeがデフォルトで対応していない設定項目には、この使い方はいい感じです。

サーバを利用するアプリケーションは、デバッグで用いるサーバと、本番運用で用いるサーバが異なります。Xcodeで、デバッグと本番とで設定を変える方法は、ターゲットを使う方法があります。ターゲットそれぞれは独立したものですから、1つのターゲットの変更は、その他のターゲットに何らの影響を与えません。これは、もしもデバッグと本番でターゲットを作っていた場合、その両方に共通した設定変更が出てきた場合には、手動でそれぞれのターゲット設定を変更しなければなりません。この構成は、ミスしたり忘れたりしてしまう原因になりえます。

xcconfigの使い方で、Xcodeが対応しているプロビジョニングなどまでxcconfigで仕込む場合もあるかもしれません。ビルドサーバーを管理運営する専任の人がいて、開発者がXcodeで何か変なことをしても影響させないなら、全てをxcconfigに持ち込むのもアリかもしれません。ですが通常は、Xcodeで扱えるものまで、設定ファイルに持ち込むと、Xcodeでいくら設定変更してもその変更が反映されず、原因がわからずに混乱してしまうだけです。

設定はその設定内容に適した場所で、かつ開発者ならどこで設定されているものが影響を与えるのかを思いつけるように、合理的に。

シェルスクリプトなどで、Mintというコマンドを使っています。

A package manager that installs and runs Swift CLI packages, https://github.com/yonaskolb/Mint

Mint で Swift 製のコマンドラインツールを管理する, https://qiita.com/usamik26/items/be813a224a2146daffb7

そんな場合に Mint が便利です。Mint は Swift Package Manager ベースで開発された Swift 製コマンドラインツールを管理するためのツールです。 例えば、SwiftLint や Carthage といったツールが管理できます。Mint を使うと、複数のバージョンをインストールしておき、バージョンを指定して実行することが可能になります。

iOSで全画面にウォータマークを入れるのにUIWiddowSceneDelegateを使うやり方

Appleが提供しているCOVID-19の濃厚接触通知のサンプルプロジェクトで、アプリのあらゆる画面に"REFERENCE ONLY"を表示させるコード部分が、面白い実装だと思ったのでメモします。

プロジェクトファイルは、Building an App to Notify Users of COVID-19 Exposure https://developer.apple.com/documentation/exposurenotification/building_an_app_to_notify_users_of_covid-19_exposure にあります。この中の ExposureNotificationApp/SceneDelegate.swift が次のコードです。

iOS13から、例えばiPadなどで1つのアプリで複数の画面を切り替えながら使う用途で、シーンという概念が導入されています。このシーンを扱う UIWindowSceneDelegate で常に前面に"Reference only"のテキストラベルを表示するUIWindowを生成して、アプリで使わせています。iOS13のSceneDelegate周りのアプリの起動シーケンス https://qiita.com/omochimetaru/items/31df103ef98a9d84ae6b が参考になります。

UIWindowSceneDelegate, Additional methods that you use to manage app-specific tasks occurring in a scene. https://developer.apple.com/documentation/uikit/uiwindowscenedelegate

アプリがシーンに対応しているのか、複数のUIWindowを扱えるのか、UIWindowSceneDelegateの実装クラス名は、Info.plistで指定します。

/post/ios-watermark-uiwindowsscenedelegate/img1.png

Application Scene Manifest、の下に Enable Multiple Windows NO があります。複数のUIWindowは持ちません。さらに下に、DelegateClassNameがあります。ここでクラス名を指定しています。

/*
See LICENSE folder for this sample’s licensing information.

Abstract:
The scene delegate.
*/

import UIKit

class SceneDelegate: UIResponder, UIWindowSceneDelegate {

    var window: WatermarkWindow!
    
    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        window = WatermarkWindow(windowScene: scene as! UIWindowScene)
        window.rootViewController = UIStoryboard(name: "Main", bundle: nil).instantiateInitialViewController()
        (window.rootViewController as! UITabBarController).selectedIndex = 1
        window.makeKeyAndVisible()
    }

    func sceneDidBecomeActive(_ scene: UIScene) {
        let rootViewController = window!.rootViewController!
        if !LocalStore.shared.isOnboarded && rootViewController.presentedViewController == nil {
            rootViewController.performSegue(withIdentifier: "ShowOnboarding", sender: nil)
        }
    }
}

class WatermarkWindow: UIWindow {
    
    let watermark = UILabel()
    
    override init(windowScene: UIWindowScene) {
        super.init(windowScene: windowScene)
        
        watermark.text = "REFERENCE ONLY"
        watermark.font = .boldSystemFont(ofSize: 48.0)
        watermark.textColor = .quaternaryLabel
        watermark.translatesAutoresizingMaskIntoConstraints = false
        watermark.transform = .init(rotationAngle: -.pi / 4.0)
        watermark.isAccessibilityElement = false
        addSubview(watermark)
        NSLayoutConstraint.activate([
            centerXAnchor.constraint(equalTo: watermark.centerXAnchor),
            centerYAnchor.constraint(equalTo: watermark.centerYAnchor)
        ])
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override func didAddSubview(_ subview: UIView) {
        super.didAddSubview(subview)
        bringSubviewToFront(watermark)
    }
}

COVID-19感染拡大防止とiOSの曝露通知の仕組み

Apple/Googleが提供する曝露通知について、その仕組みとその働きの考察をプレゼンしました。

仕組みの概要

SARS-CoV-2の感染の目安は、ウイルスを外部に排出している方との、1~2メートル程度の距離で15分以上という、濃厚接触を持ったかどうかです。

感染拡大防止には、実効再生産数、対策を行なっている状態で平均して1人あたりが感染させる人数、を1以下にすることが必要です。日本での感染拡大防止の活動は、陽性判定が出た方にインタビューをして、人の記憶を頼りにいつ誰と接触したかを調べて、潜伏期にあるかもしれない方々に人との濃厚接触を低減するようお願いをすることです。この濃厚接触を通知する仕組みが、曝露通知です。

曝露通知は、Apple/Googleが提供するフレームワークと、各国それぞれの行政が開発運営するアプリと通知サーバの、2つで構成されます。

フレームワークの機能は、識別子の生成と送信、識別子の受信と記録、識別子の照合の3つです。それぞれの端末が識別子をBLEでブロードキャストします。また同時に、周囲のブロードキャストをスキャンして、その識別子を記録します。陽性判定された方は、アプリを通じて、ウイルスを排出していた期間の識別子を、サーバーにアップロードします。陽性判定された方々の識別子は、それぞれのアプリに通知されて、デバイスの内部で識別子の照合が実行されて、濃厚接触があった場合はアプリにその旨が表示されます。

識別子の送出と記録そして照合という基本部分は、Apple/Googleが開発する部分で、アプリケーションが識別子などの具体的な情報を直接扱うことはできません。アプリケーションの機能は、曝露通知の利用を開始する、濃厚接触があった場合にそれを知らせる、陽性判定が出た時にそれを入力する、の3つです。これらの部分は、利用者の合意と運営が必要で、それぞれの国ごとの行政活動ですから、アプリケーションとして切り出しになります。

通知サーバーも、それぞれの国の運営になります。仕組み自体は、Apple Notification Serviceなど、スマホの通知の実装と同じようなものです。Apple/Googleが提供する通知サービスに、運営者が提供するサーバーから通知したい情報を渡せば、それが対象デバイスに配布されていきます。

質問と回答

Q: 感染していないのに陽性だと入力して、いたずらされるのでは? A: 陽性の場合にアプリにそれを入力するには、日本では保健所が発行する認証コードが必要です。パスワードがない他人のアカウントにログインしようとするようなものですから、いたずらはできないのでしょう。

Q: アプリの配布6割とか無理では? A: 人口が小さく教育水準も高そうなシンガポールで、政府が独自に提供した濃厚接触検出アプリがインストール率2割らしい(根拠未調査)です。シンガポールの人口は563万人、東京都の人口927万人の半分くらいの規模でもそれですから、国の単位で6割は、自然に達成できる値ではないと思います。

法的な根拠に基づきインストールを強制するのも困難でしょう。例えばですが、飲酒運転で検挙された場合に問答無用で解雇となるルールがある会社は少なくないでしょう。濃厚接触通知のアプリをインストールしていないことが、社会の利益に貢献しないこととして、なんとく空気感として、インストールせざるを得ない雰囲気にでもするのかもしれません。

Q: 標準アプリとして配布、あるいはヘルスアプリに機能統合してしまえないのか。 A: 濃厚通知の仕組みを初めて聞いた時に、通知サーバーまで含めてApple/Googleが提供するのかと思っていました。でも、それでは陽性だと入力するのが本当に陽性なのか、誰かがそれを保証しないと、いたずらする人がいれば、使い物にならなくなります。標準アプリにした場合、この陽性だと確認して保証する仕組み部分が、処理として入れられないでしょう。キャリアの端末は、自社サービスのアプリをプリインストールしていますが、そのようなプリインストールはありなのかも?

Q: 国を超えた移動をする方は、これを使えるのか。 A: アプリの運営が国単位になるため、訪問国のアプリをインストールして帰国後も2週間程度はアンインストールせずにおけば使えるはずです。

濃厚接触した誰かが陽性であった場合は、iOS/Androidのデバイス通知は国を超えて機能するでしょうから、曝露通知が得られると思われます。ですが、自分に陽性判定に出た時には、アプリに陽性だと入力するための認証コードは、日本の保健行政機関から認証コードを払い出してもらわなければなりません。国の間での行政連携でもないと、できそうにない気がしますが、それがどうなるかはわかりません。あとは、通知サーバーは国ごとの運営になるため、もしもファイヤーウォールなどのために、他国の通知サーバーにアクセスできない場合は、陽性判定が出た場合でもそれを知らせることはできなさそうです。