$30 off During Our Annual Pro Sale. View Details »

Yappliにおけるパーミッション要求の課題と改善 / Challenges and Improvements of Permission Requests in Yappli

Nao-RandD
October 17, 2023

Yappliにおけるパーミッション要求の課題と改善 / Challenges and Improvements of Permission Requests in Yappli

Yappli Tech Conference 2023 における発表内容です。
https://yappli.connpass.com/event/295001/

Nao-RandD

October 17, 2023
Tweet

Other Decks in Programming

Transcript

  1. Yappliにおける

    パーミッション要求の


    課題と改善

    View Slide

  2. Speaker
    プロダクト開発本部 開発1部 iOSグループ


    iOSエンジニア
    菅 直之
    2022年9⽉からヤプリでiOSエンジニアとして

    働いています



    趣味は登⼭と将棋で、最近は電⼦ピアノにハマって
    います


    @Nao_RandD

    View Slide

  3. 01


    02


    03


    04


    05


    iOSにおけるパーミッション要求


    Yappliにおけるパーミッション要求


    基盤改善における課題と今後実現したいこと


    改善までの道のり


    まとめ


    View Slide

  4. 01 iOSにおける


    パーミッション要求

    View Slide

  5. 0 1
    iOSにおけるパーミッション要求
    iOSにおけるパーミッション要求
    パーミッション要求とは?


    • アプリがデバイスの特定機能やデータに

    アクセスするために必要となる

    例:位置情報、カメラ、プッシュ通知など

    • ユーザーがアプリにどのような特定機能‧

    アクセスを許可するかを明⽰的にコントロー
    ルできる

    View Slide

  6. 0 1
    iOSにおけるパーミッション要求
    iOSにおけるパーミッション要求
    開発者に期待されること


    • 必要最低限のパーミッションのみを

    要求すること

    • プライバシーの側⾯でデータや

    リソース利⽤の透明性を担保する
    https://developer.apple.com/design/human-interface-guidelines/privacy

    View Slide

  7. 0 1
    iOSにおけるパーミッション要求
    iOSにおけるパーミッション要求
    パーミッション要求のダイアログ


    • ダイアログ表⽰処理はアプリで呼び出し

    システムによって実⾏される

    • 同時に複数呼び出すとダイアログが重複する

    動作となりユーザー体験を損なう

    • ホーム画⾯など要求処理が集中する場所では

    呼び出しに配慮が必要になる

    View Slide

  8. 02 Yappliにおける


    パーミッション要求

    View Slide

  9. 0 2
    Yappliにおけるパーミッション要求
    Yappliにおけるパーミッション要求
    Yappliはノーコードのアプリプラットフォーム


    • 650社以上で導⼊されており、約800アプリを提供している


    • アプリ要件に合わせて40種以上の機能がある

    View Slide

  10. アプリごとのパーミッション


    • 同じプラットフォーム上でアプリごとに必要な

    パーミッションが異なる


    0 2
    Yappliにおけるパーミッション要求
    Yappli
    Yappliにおけるパーミッション要求

    View Slide

  11. 03 基盤改善における


    課題と今後実現したいこと

    View Slide

  12. 1
    2
    基盤改善前の課題
    今後実現したいこと
    • 事前説明画⾯の機能追加
    03 基盤改善における課題と今後実現したいこと
    • 可読性‧保守性の低さ


    • 要求処理のボイラープレート化


    • 同時に複数の要求を扱うのが難しい

    View Slide

  13. パーミッション要求はシステム実⾏であり、

    順次実⾏のためにコールバックで実装している


    コールバックの実⾏は開発者の責務となり、

    呼ばないことによるコンパイルエラーは出ない


    1 基盤改善前の課題
    03 基盤改善における課題と今後実現したいこと
    可読性‧保守性の低さ
    func hoge() {


    requestPermissionA {


    // ॏཁͳޙଓॲཧ


    }


    }


    func requestPermissionA(


    completion: @escaping () -> Void) {


    // PermissionAͷύʔϛογϣϯཁٻॲཧ


    // ...


    if isAuthorize {


    // ޙଓͷॲཧ͕࣮ߦ͞ΕΔ


    completion()


    } else {


    // Կ΋͠ͳ͔ͬͨ


    }


    }


    パーミッションに関わる処理はストア審査リジェクト、
    機能提供できないなど⼤きな問題になる可能性が⾼い

    View Slide

  14. パーミッションの種類によって

    要求処理に必要な実装は異なる


    機能単位で要求処理を別々に実装しており


    処理として共通化されていない


    1 基盤改善前の課題
    03 基盤改善における課題と今後実現したいこと
    要求処理のボイラープレート化 struct ModuleA {


    typealias Callback = (Bool) -> Void


    func requestLocationPermission(


    _ completion: @escaping Callback) {


    // Ґஔ৘ใͷύʔϛογϣϯཁٻॲཧ


    }


    func requestATTPermission(_ completion: @escaping Callback)
    {


    // ATT(AppTrackingTransparancy)ͷύʔϛογϣϯཁٻॲཧ


    }


    }


    struct ModuleB {


    typealias Callback = (Bool) -> Void


    func requestLocationPermission(


    _ completion: @escaping Callback) {


    // Ґஔ৘ใͷύʔϛογϣϯཁٻॲཧ


    }


    }


    同じパーミッションの実装が


    必要な機能ごとに増えていく

    View Slide

  15. ホーム画⾯など同時に複数のパーミッション
    を組み合わせて要求したい場⾯がある


    1 基盤改善前の課題
    03 基盤改善における課題と今後実現したいこと
    同時に複数の要求を扱うのが難しい
    func requestMultiPermission(


    _ completion: @escaping () -> Void) {


    requestLocationPermission { _ in


    requestATTPermission { _ in


    requestBluetoothPermission { _ in


    // ޙଓॲཧ


    }


    }


    }


    }


    要求処理が増えるたびに


    ネストが深くなってしまう

    View Slide

  16. それぞれのパーミッション要求前に事前説明が欲しい要望があった


    2 今後実現したいこと
    03 基盤改善における課題と今後実現したいこと
    事前説明画⾯の機能追加
    https://developer.apple.com/jp/design/human-interface-guidelines/privacy#Pre-alert-screens-windows-or-views
    パーミッション要求前にユーザーに対して、

    アプリで⽤いる⽤途や提供する機能を説明する
    画⾯のこと


    許諾率の向上となりAppleも推奨している
    事前説明画⾯とは?

    View Slide

  17. 2 今後実現したいこと
    03 基盤改善における課題と今後実現したいこと
    事前説明画⾯の機能追加
    パーミッション要求
    事前説明画⾯表⽰
    ユーザーが選択後に
    後続の処理

    View Slide

  18. 2 今後実現したいこと
    03 基盤改善における課題と今後実現したいこと
    事前説明画⾯の機能追加
    パーミッション要求
    事前説明画⾯表⽰
    ユーザーが選択後に
    後続の処理
    パーミッション要求前後の処理の差し込みにも柔軟に対応できる実装を⽬指す

    View Slide

  19. 3つの課題
    今後実現したいこと
    ⬜︎
    可読性‧保守性の低さ


    ⬜︎
    要求処理のボイラープレート化


    ⬜︎
    同時に複数の要求を扱うのが難しい
    ⬜︎
    事前説明画⾯の機能追加
    03 基盤改善における課題と今後実現したいこと
    ✅ 改善におけるチェックリスト

    View Slide

  20. 04 改善までの道のり

    View Slide

  21. STEP 2
    STEP 1
    STEP 3
    Swift Concurrency導⼊
    インターフェースを共通化
    04 改善までの道のり
    要求処理のワークフロー化

    View Slide

  22. STEP 2
    STEP 1
    STEP 3
    Swift Concurrency導⼊
    インターフェースを共通化
    要求処理のワークフロー化
    04 改善までの道のり

    View Slide

  23. 1
    2
    Swift Concurrencyのメリット
    導⼊における考慮
    • Swift Concurrencyについて


    • async/awaitによる可読性向上
    • パーミッションごとの要求処理の差分


    • Delegateパターンの吸収
    04 改善までの道のり- STEP
    1
    Swift Concurrency導⼊
    課題
    今後実現したいこと
    ⬜︎
    可読性‧保守性の低さ


    ⬜︎
    要求処理のボイラープレート化


    ⬜︎
    同時に複数の要求を扱うのが難しい
    ⬜︎
    事前説明画⾯の機能追加
    ✅ 改善におけるチェックリスト

    View Slide

  24. Swift
    5
    .
    5
    から⾔語機能として登場した


    ⾮同期処理‧並列処理のコードを簡潔かつ安
    全に記述できる


    async/awaitを使⽤することができる
    1 Swift Concurrencyのメリット
    04 改善までの道のり- STEP
    1
    Swift Concurrency導⼊
    Swift Concurrencyについて
    https://docs.swift.org/swift-book/documentation/the-swift-programming-language/concurrency/

    View Slide

  25. async/awaitを⽤いることで⾮同期処理を

    同期処理と同じような書き⽅で実装できる


    コールバックのネストが深い処理などを

    可読性⾼く実装する助けになる


    1 Swift Concurrencyのメリット
    04 改善までの道のり- STEP
    1
    Swift Concurrency導⼊
    async/awaitによる可読性向上
    // ίʔϧόοΫͰͷ࣮ߦ


    foo { x in


    bar(x) { y in


    baz(y) { z in


    // ޙଓͷॲཧ


    }


    }


    }


    // async/awaitͰͷ࣮ߦ


    let x = await foo()


    let y = await bar(x)


    let z = await baz(y)


    パーミッション要求処理を


    async/awaitに落とし込んでいく

    View Slide

  26. async/awaitが対応したものがAPIが

    提供されていれば素直に実装する


    プッシュ通知のUNUserNoti
    fi
    cationなどは


    async/awaitで呼び出せるAPIがある


    requestAuthorization(for: )


    2 導⼊における考慮
    04 改善までの道のり- STEP
    1
    Swift Concurrency導⼊
    async/await の I/F が⽤意されている ⭕
    func request() async -> Bool {


    do {


    let nc = UNUserNotificationCenter.current()


    return try await nc.requestAuthorization(


    options: [.badge,


    .sound,


    .alert])


    } catch {


    // ΤϥʔϋϯυϦϯά


    }


    }


    https://developer.apple.com/documentation/usernoti
    fi
    cations/unusernoti
    fi
    cationcenter/1649527-requestauthorization

    View Slide

  27. 代表的なケース:


    Delegateでパーミッションのステータス変化を

    検知する必要がある


    例:Bluetoothや位置情報


    そのままasync/awaitで置き換えられない


    2 導⼊における考慮
    04 改善までの道のり- STEP
    1
    Swift Concurrency導⼊
    async/await の I/F が⽤意されていない ❌
    class BluetoothPermission: NSObject,


    CBCentralManagerDelegate {


    private var centralManager: CBCentralManager?


    typealias Status = CBManagerAuthorization


    func request() {


    // ύʔϛογϣϯεςʔλεʹԠͯ͡ૣظϦλʔϯ


    // ...


    // CBCentralManagerΛΠϯελϯεԽ͢ΔͱμΠΞϩάදࣔ


    centralManager = CBCentralManager(delegate: self,


    queue: nil)


    }


    /// εςʔλε͕มߋ͞ΕΔͱݺ͹ΕΔDelegateϝιου


    func centralManagerDidUpdateState(


    _ central: CBCentralManager) {


    let status = CBManager.authorization


    // ύʔϛογϣϯεςʔλε͝ͱͷॲཧ


    }


    }


    View Slide

  28. 代表的なケース:


    Delegateでパーミッションのステータス変化を

    検知する必要がある


    例:Bluetoothや位置情報


    そのままasync/awaitで置き換えられない


    2 導⼊における考慮
    04 改善までの道のり- STEP
    1
    Swift Concurrency導⼊
    async/await の I/F が⽤意されていない ❌
    https://developer.apple.com/documentation/swift/withcheckedcontinuation(function:_:)
    func request() async -> Status {


    // εςʔλεʹԠͯ͡ૣظϦλʔϯ


    // ...


    // CBCentralManagerΛΠϯελϯεԽ͢ΔͱμΠΞϩάදࣔ


    centralManager = CBCentralManager(delegate: self,


    queue: nil)


    return await withCheckedContinuation {


    [weak self] (continuation: Continuation) in


    guard let self = self else { return }


    self.continuation = continuation


    }


    }


    func centralManagerDidUpdateState(


    _ central: CBCentralManager) {


    let status = CBManager.authorization


    if status == .notDetermined { return }


    // resumeʹεςʔλεΛ౉͢


    continuation?.resume(returning: status)


    continuation = nil


    }


    withCheckedContinuation
    を利⽤する

    View Slide

  29. 1
    2
    Swift Concurrencyのメリット
    導⼊における考慮
    • Swift Concurrencyについて


    • async/awaitによる可読性向上
    • パーミッションごとの要求処理の差分


    • Delegateパターンの吸収
    04 改善までの道のり- STEP
    1
    Swift Concurrency導⼊
    課題
    今後実現したいこと
    ✅ 可読性‧保守性の低さ


    ⬜︎
    要求処理のボイラープレート化


    ⬜︎
    同時に複数の要求を扱うのが難しい
    ⬜︎
    事前説明画⾯の機能追加
    ✅ 改善におけるチェックリスト

    View Slide

  30. STEP 1
    STEP 3
    STEP 2
    Swift Concurrency導⼊
    インターフェースを共通化
    要求処理のワークフロー化
    04 改善までの道のり

    View Slide

  31. 1
    2
    共通化において実現したいこと
    実装
    • 異なるパーミッション要求処理の共通化


    • Managerクラスを定義してI/Fも共通化
    • 全体図


    • コードに落とし込む
    04 改善までの道のり- STEP
    2
    インターフェースを共通化
    課題
    今後実現したいこと
    ✅ 可読性‧保守性の低さ


    ⬜︎
    要求処理のボイラープレート化


    ⬜︎
    同時に複数の要求を扱うのが難しい
    ⬜︎
    事前説明画⾯の機能追加
    ✅ 改善におけるチェックリスト

    View Slide

  32. 種別によって別々に実装されている処理を
    「パーミッション要求」として共通化したい


    要求処理を含むプロトコルとして定義する



    パーミッション種別ごとの処理に


    呼び元が依存しないようにする
    1 共通化において実現したいこと
    04 改善までの道のり- STEP
    2
    インターフェースを共通化
    異なるパーミッション要求を共通化する

    View Slide

  33. パーミッション要求を共通化するのに合わせて

    処理実⾏も1つに集約する


    異なる機能から同時に複数のパーミッション要求
    がされた場合にも順次実⾏する


    (前述のダイアログ重複を防⽌するため)


    1 共通化において実現したいこと
    04 改善までの道のり- STEP
    2
    インターフェースを共通化
    Managerクラスを定義してI/Fも共通化
    Manager


    I/F
    Managerにパーミッションを
    渡した順序で順次実⾏する

    View Slide

  34. 1 共通化において実現したいこと
    04 改善までの道のり- STEP
    2
    インターフェースを共通化
    Managerクラスを定義してI/Fも共通化
    Manager


    I/F
    Managerにパーミッションを
    渡した順序で順次実⾏する
    要件


    同時に複数のパーミッション要求がされた場合
    にも順次実⾏

    View Slide

  35. 1 共通化において実現したいこと
    04 改善までの道のり- STEP
    2
    インターフェースを共通化
    Managerクラスを定義してI/Fも共通化
    機能A


    パーミッションA


    パーミッションB


    機能B


    パーミッションC


    Manager


    I/F
    Managerにパーミッションを
    渡した順序で順次実⾏する
    要件


    同時に複数のパーミッション要求がされた場合
    にも順次実⾏

    View Slide

  36. 1 共通化において実現したいこと
    04 改善までの道のり- STEP
    2
    インターフェースを共通化
    Managerクラスを定義してI/Fも共通化
    機能A


    パーミッションA


    パーミッションB


    機能B


    パーミッションC


    Manager


    I/F
    Managerにパーミッションを
    渡した順序で順次実⾏する
    要件


    同時に複数のパーミッション要求がされた場合
    にも順次実⾏

    View Slide

  37. キューでパーミッション要求処理をまとめて


    管理して追加された順に実⾏する
    1 共通化において実現したいこと
    04 改善までの道のり- STEP
    2
    インターフェースを共通化
    Managerクラスを定義してI/Fも共通化
    機能A


    パーミッションB


    機能B


    パーミッションC


    Manager


    I/F


    キューに追加
    キュー


    実⾏タスク


    パーミッションA


    View Slide

  38. 1 共通化において実現したいこと
    04 改善までの道のり- STEP
    2
    インターフェースを共通化
    Managerクラスを定義してI/Fも共通化
    機能A


    パーミッションA


    機能B


    パーミッションC


    Manager


    I/F


    キューに追加
    キュー


    実⾏タスク


    パーミッションB


    キューでパーミッション要求処理をまとめて


    管理して追加された順に実⾏する

    View Slide

  39. 1 共通化において実現したいこと
    04 改善までの道のり- STEP
    2
    インターフェースを共通化
    Managerクラスを定義してI/Fも共通化
    機能A


    機能B


    パーミッションC


    Manager


    I/F


    キューに追加
    キュー


    実⾏タスク


    パーミッションB


    パーミッションA


    パーミッションAを実⾏中


    (ダイアログ表⽰状態)
    キューでパーミッション要求処理をまとめて


    管理して追加された順に実⾏する

    View Slide

  40. 1 共通化において実現したいこと
    04 改善までの道のり- STEP
    2
    インターフェースを共通化
    Managerクラスを定義してI/Fも共通化
    機能A


    機能B


    パーミッションC


    Manager


    I/F


    キューに追加
    キュー


    実⾏タスク


    パーミッションB


    パーミッションA


    パーミッションAを実⾏中


    (ダイアログ表⽰状態)
    Managerが実⾏中に


    パーミッション要求処理

    → キューへの追加
    キューでパーミッション要求処理をまとめて


    管理して追加された順に実⾏する

    View Slide

  41. 1 共通化において実現したいこと
    04 改善までの道のり- STEP
    2
    インターフェースを共通化
    Managerクラスを定義してI/Fも共通化
    機能A


    機能B


    Manager


    I/F


    キューに追加
    キュー


    実⾏タスク


    パーミッションB


    パーミッションA


    キューに追加され


    順番に実⾏される
    パーミッションC


    キューでパーミッション要求処理をまとめて


    管理して追加された順に実⾏する
    パーミッションAを実⾏中


    (ダイアログ表⽰状態)

    View Slide

  42. キューでパーミッション要求処理をまとめて


    管理して追加された順に実⾏する
    1 共通化において実現したいこと
    04 改善までの道のり- STEP
    2
    インターフェースを共通化
    Managerクラスを定義してI/Fも共通化
    Manager


    I/F


    キューに追加
    キュー


    実⾏タスク


    パーミッションB


    パーミッションA


    キューに追加され


    順番に実⾏される
    パーミッションC


    パーミッションAを実⾏中


    (ダイアログ表⽰状態)
    この動作を満たすように


    実装していく

    View Slide

  43. パーミッション要求を共通化した
    PermissionRequestをプロトコルで定義する


    PermissionManagerにaddされたものを


    順次実⾏していくようにする


    2 実装
    04 改善までの道のり- STEP
    2
    インターフェースを共通化
    全体図

    View Slide

  44. パーミッション要求をPermissionRequest
    としてプロトコルに定義


    パーミッションステータスも
    PermissionStatusとしてプロトコルに定義


    2 実装
    04 改善までの道のり- STEP
    2
    インターフェースを共通化
    コードに落とし込む(パーミッション要求)

    View Slide

  45. 2 実装
    04 改善までの道のり- STEP
    2
    インターフェースを共通化
    // MARK: PermissionRequest


    protocol PermissionRequest {


    func request() async -> PermissionStatus


    }


    // MARK: PermissionStatus


    protocol PermissionStatus {}


    パーミッション要求をPermissionRequest
    としてプロトコルに定義


    パーミッションステータスも
    PermissionStatusとしてプロトコルに定義


    コードに落とし込む(パーミッション要求)

    View Slide

  46. 2 実装
    04 改善までの道のり- STEP
    2
    インターフェースを共通化
    コードに落とし込む(Managerクラス)
    パーミッション要求(PermissionRequest)
    を実⾏するPermissionMangerを実装する


    View Slide

  47. PermissionRequestをキューで管理する


    外部からキューに追加するメソッドを公開する


    実⾏中を⽰すステータスとタスクを


    実⾏するメソッドを⽤意する
    2 実装
    04 改善までの道のり- STEP
    2
    インターフェースを共通化
    コードに落とし込む(Managerクラス)

    View Slide

  48. 必要な要素


    • PermissionRequestを⼊れるキュー


    • 実⾏中を管理できるOperationStatus


    • I/Fとして外部からキューに追加するadd()


    • キューにあるPermissionRequestを

    順次実⾏するexecuteRequest()


    2 実装
    04 改善までの道のり- STEP
    2
    インターフェースを共通化
    @MainActor


    final class PermissionManager {


    static let shared = PermissionManager()


    private init() {}


    private enum OperationStatus {


    case running


    case waiting


    }


    private var queue: [PermissionRequest] = []


    private var operationStatus: OperationStatus = .waiting


    func add(request: PermissionRequest) {


    // ...


    // ࣮ߦதͰͳ͚Ε͹ executeRequest()


    }


    private func executeRequest() async {


    // ...


    }


    }


    コードに落とし込む(Managerクラス)

    View Slide

  49. @MainActor


    final class PermissionManager {


    static let shared = PermissionManager()


    private init() {}


    private enum OperationStatus {


    case running


    case waiting


    }


    private var queue: [PermissionRequest] = []


    private var operationStatus: OperationStatus = .waiting


    func add(request: PermissionRequest) {


    // ...


    // ࣮ߦதͰͳ͚Ε͹ executeRequest()


    }


    private func executeRequest() async {


    // ...


    }


    }


    必要な要素


    • PermissionRequestを⼊れるキュー


    • 実⾏中を管理できるOperationStatus


    • I/Fとして外部からキューに追加するadd()


    • キューにあるPermissionRequestを

    順次実⾏するexecuteRequest()


    2 実装
    04 改善までの道のり- STEP
    2
    インターフェースを共通化
    排他的なキューへのアクセスとなるように
    PermissionManagerを@MainActorにする
    コードに落とし込む(Managerクラス)

    View Slide

  50. 実装後


    • PermissionManagerにパーミッション要求を

    追加するだけで実⾏できる


    • 同時に複数の要求処理が追加されても順次実⾏で

    パーミッション要求を⾏える


    2 実装
    04 改善までの道のり- STEP
    2
    インターフェースを共通化
    // MARK: AsIs


    func requestMultiPermission() {


    requestLocationPermission { _ in


    requestATTPermission { _ in


    }


    }


    }


    // MARK: ToBe


    PermissionManager.shared.add(


    request: LocationPermission())


    PermissionManager.shared.add(


    request: ATTPermission())


    コードに落とし込む(Managerクラス)

    View Slide

  51. 実装後


    • PermissionManagerにパーミッション要求を

    追加するだけで実⾏できる


    • 同時に複数の要求処理が追加されても順次実⾏で

    パーミッション要求を⾏える


    2 実装
    04 改善までの道のり- STEP
    2
    インターフェースを共通化
    // MARK: AsIs


    func requestMultiPermission() {


    requestLocationPermission { _ in


    requestATTPermission { _ in


    }


    }


    }


    // MARK: ToBe


    PermissionManager.shared.add(


    request: LocationPermission())


    PermissionManager.shared.add(


    request: ATTPermission())


    同時に呼び出す要求処理が


    増えてもネストが深くならない
    コードに落とし込む(Managerクラス)

    View Slide

  52. 1
    2
    共通化において実現したいこと
    実装
    • 異なるパーミッション要求処理の共通化


    • 組み合わせても使⽤できる仕組み
    • コードに落とし込む
    04 改善までの道のり- STEP
    2
    インターフェースを共通化
    課題
    今後実現したいこと
    ✅ 可読性‧保守性の低さ


    ✅ 要求処理のボイラープレート化


    ✅ 同時に複数の要求を扱うのが難しい
    ⬜︎
    事前説明画⾯の機能追加
    ✅ 改善におけるチェックリスト

    View Slide

  53. STEP 2
    STEP 1
    STEP 3
    Swift Concurrency導⼊
    インターフェースを共通化
    要求処理のワークフロー化
    04 改善までの道のり

    View Slide

  54. 1
    2
    要求処理を組み合わせるワークフロー
    実装
    • 要求処理に紐づいた処理も共通化したい
    • 全体図


    • コードに落とし込む
    04 改善までの道のり- STEP
    3
    要求処理のワークフロー化
    課題
    今後実現したいこと
    ✅ 可読性‧保守性の低さ


    ✅ 要求処理のボイラープレート化


    ✅ 同時に複数の要求を扱うのが難しい
    ⬜︎
    事前説明画⾯の機能追加
    ✅ 改善におけるチェックリスト

    View Slide

  55. パーミッション要求と紐づいた処理も

    PermissionMangerのI/Fで使えるようにしたい


    1 要求処理を組み合わせるワークフロー
    要求処理に紐づいた処理も共通化したい
    04 改善までの道のり- STEP
    3
    要求処理のワークフロー化

    View Slide

  56. パーミッション要求と紐づいた処理も

    PermissionMangerのI/Fで使えるようにしたい


    ワークフローを利⽤できるようにする
    1 要求処理を組み合わせるワークフロー
    要求処理に紐づいた処理も共通化したい
    04 改善までの道のり- STEP
    3
    要求処理のワークフロー化

    View Slide

  57. パーミッション要求と紐づいた処理も

    PermissionMangerのI/Fで使えるようにしたい


    ワークフローを利⽤できるようにする


    ワークフローとパーミッション要求を共通化した


    PermissionActionを新たに定義する
    1 要求処理を組み合わせるワークフロー
    要求処理に紐づいた処理も共通化したい
    04 改善までの道のり- STEP
    3
    要求処理のワークフロー化

    View Slide

  58. ワークフローとパーミッション要求を


    共通化したPermissionActionを定義する
    2 実装
    全体図
    04 改善までの道のり- STEP
    3
    要求処理のワークフロー化

    View Slide

  59. ワークフローとパーミッション要求を

    共通化したPermissionActionを定義する


    PermissionRequestはPermissionAction

    に準拠する
    2 実装
    全体図
    04 改善までの道のり- STEP
    3
    要求処理のワークフロー化

    View Slide

  60. ワークフローとパーミッション要求を

    共通化したPermissionActionを定義する


    PermissionRequestはPermissionAction

    に準拠する


    PermissionManagerはPermissionAction

    を順次実⾏する
    2 実装
    全体図
    04 改善までの道のり- STEP
    3
    要求処理のワークフロー化

    View Slide

  61. 2 実装
    // MARK: PermissionAction


    protocol PermissionAction {


    func execute() async


    }


    // MARK: PermissionRequest


    protocol PermissionRequest: PermissionAction {


    func request() async -> PermissionStatus


    }


    // Protocol ExtensionͰrequestΛݺͿ͜ͱͰ

    // PermissionRequestଆ͸࣮૷ʹ͓͍ͯ

    // PermissionActionͷ࣮૷Λҙࣝ͠ͳͯ͘ྑ͘͢Δ


    extension PermissionRequest {


    func execute() async {


    _ = await request()


    }


    }


    protocol PermissionStatus {}


    コードに落とし込む
    (PermissionRequestプロトコル)
    04 改善までの道のり- STEP
    3
    要求処理のワークフロー化

    View Slide

  62. 2 実装
    // PermissionRequest͸͜Ε·Ͱ௨Γͷ࣮૷Ͱྑ͍ʢલड़ʣ


    struct PermissionA: PermissionRequest {


    func request() async -> PermissionStatus {


    // PermissionAͷύʔϛογϣϯཁٻॲཧ


    }


    }


    struct PermissionB: PermissionRequest {


    func request() async -> PermissionStatus {


    // PermissionBͷύʔϛογϣϯཁٻॲཧ


    }


    }


    // ෳ਺ͷύʔϛογϣϯΛऔಘ͢Δύλʔϯ΋ϫʔΫϑϩʔʹͰ͖Δ


    struct MultiPermissionWorkflow: PermissionAction {


    func execute() async {


    let statusA = await PermissionA().request()


    let statusB = await PermissionB().request()


    }


    }


    コードに落とし込む

    (ワークフローとパーミッション要求)
    04 改善までの道のり- STEP
    3
    要求処理のワークフロー化

    View Slide

  63. 実装後


    • 各機能からPermissionManagerに

    パーミッション要求とワークフローを

    キューに追加するのみで実⾏できる


    2 実装
    struct LocationPermission: PermissionRequest {


    func request() async -> PermissionStatus {


    // Ґஔ৘ใͷύʔϛογϣϯཁٻॲཧ


    }


    }


    // ෳ਺ͷύʔϛογϣϯΛཁٻ͢ΔϫʔΫϑϩʔ


    struct MultiPermissionWorkflow: PermissionAction {


    func execute() async {


    await BluetoothPermission().request()


    // Bluetoothͷཁٻॲཧޙʹඞཁͳॲཧ


    await ATTPermission().request()


    }


    }


    // ϫʔΫϑϩʔ΋୯ମͷύʔϛογϣϯ΋ಉ͡Α͏ʹݺͼग़ͤΔ


    PermissionManager.shared.add(


    action: MultiPermissionWorkflow())


    PermissionManager.shared.add(


    action: LocationPermission())


    04 改善までの道のり- STEP
    3
    要求処理のワークフロー化
    コードに落とし込む

    (ワークフローとパーミッション要求)

    View Slide

  64. // MARK: ࣄલઆ໌ը໘ΛؚΜͩύʔϛογϣϯཁٻ


    struct PreAlertScreenWorkflow: PermissionAction {


    func execute() async {


    // ͜͜ʹࣄલઆ໌ը໘ͷॲཧʢҐஔ৘ใʣ


    await LocationPermission().request()


    // ͜͜ʹࣄલઆ໌ը໘ͷॲཧʢATTʣ


    await ATTPermission().request()


    // ޙଓॲཧ


    }


    }


    // ݺͼݩ


    PermissionManager.shared.add(


    action: PreAlertScreenWorkflow())


    実装後


    • 各機能からPermissionManagerに

    パーミッション要求とワークフローを

    キューに追加するのみで実⾏できる


    2 実装
    04 改善までの道のり- STEP
    3
    要求処理のワークフロー化
    コードに落とし込む

    (ワークフローとパーミッション要求)
    事前説明画⾯処理もワークフローとして


    PermissionManagerで扱える

    View Slide

  65. 1
    2
    要求処理を組み合わせるワークフロー
    実装
    • 要求処理に紐づいた処理も共通化したい
    • 全体図


    • コードに落とし込む
    04 改善までの道のり- STEP
    3
    要求処理のワークフロー化
    課題
    今後実現したいこと
    ✅ 可読性‧保守性の低さ


    ✅ 要求処理のボイラープレート化


    ✅ 同時に複数の要求を扱うのが難しい
    ✅ 事前説明画⾯の機能追加
    ✅ 改善におけるチェックリスト

    View Slide

  66. 05 まとめ

    View Slide

  67. 取り組んだこと
    Yappliにおけるパーミッション要求処理の課題と改善
    Swift Concurrency導⼊


    パーミッション要求処理の共通化


    要求処理のワークフロー化
    現状の課題改善‧事前説明画⾯の下準備に!
    05 まとめ

    View Slide

  68. ご清聴ありがとうございました
    Yappliにおけるパーミッション要求の課題と改善

    View Slide