Lock in $30 Savings on PRO—Offer Ends Soon! ⏳

デバッグメニューのメンテナンスが大変だったので、専用アプリを作りました。 / iOSDC Ja...

FromAtom
September 20, 2020

デバッグメニューのメンテナンスが大変だったので、専用アプリを作りました。 / iOSDC Japan 2020

FromAtom

September 20, 2020
Tweet

More Decks by FromAtom

Other Decks in Technology

Transcript

  1. アジェンダ • デバッグメニューとは • 背景 • 仕組み • 実装方法 •

    デバッグメニューアプリ作りのコツ • CI時のコツ • メリットとデメリット
  2. アジェンダ • デバッグメニューとは • 背景 • 仕組み • 実装方法 •

    デバッグメニューアプリ作りのコツ • CI時のコツ • メリットとデメリット
  3. アジェンダ • デバッグメニューとは • 背景 • 仕組み • 実装方法 •

    デバッグメニューアプリ作りのコツ • CI時のコツ • メリットとデメリット
  4. 弊社の背景 • 7つのiOSアプリを開発・提供 • アプリによって下記が異なる ‣ メニューの有無 ‣ アクセス方法 ‣

    UI ‣ 実装方法 独自デバッグメニュー なし なし 独自デバッグメニュー 独自デバッグメニュー なし なし
  5. アジェンダ • デバッグメニューとは • 背景 • 仕組み • 実装方法 •

    デバッグメニューアプリ作りのコツ • CI時のコツ • メリットとデメリット
  6. アジェンダ • デバッグメニューとは • 背景 • 仕組み • 実装方法 •

    デバッグメニューアプリ作りのコツ • CI時のコツ • メリットとデメリット
  7. アジェンダ • デバッグメニューとは • 背景 • 仕組み • 実装方法 •

    デバッグメニューアプリ作りのコツ • CI時のコツ • メリットとデメリット
  8. App import Foundation final class App { let name: String

    let bundleID: String var groups: [Group] = [] init(name: String, bundleID: String) { self.name = name self.bundleID = bundleID } func add(group: Group) { groups.append(group) } }
  9. let apps = [ App(name: "iOSDC Japan 2020", bundleID: "com.example.iosdc")

    App(name: "pixiv Sketch", bundleID: "com.example.sketch"), App(name: "BOOTH", bundleID: "com.example.booth"), App(name: "pixiv", bundleID: "com.example.pixiv"), App(name: "pixivコミック", bundleID: "com.example.comic") ] App
  10. let apiGroup = Group(title: "API", selectors: [ BoolSelector(key: Keys.changeAPI.rawValue, title:

    "接続先APIを差し替える"), StringSelector(key: Keys.apiEndpoint.rawValue, title: "接続先API", values: [ "https://example.com/api", "https://example.com/sandbox-api", "https://example.com/staging-api", ]) ]) Group
  11. let apiGroup = Group(title: "API", selectors: [ BoolSelector(key: Keys.changeAPI.rawValue, title:

    "接続先APIを差し替える"), StringSelector(key: Keys.apiEndpoint.rawValue, title: "接続先API", values: [ "https://example.com/api", "https://example.com/sandbox-api", "https://example.com/staging-api", ]) ]) let debugModeGroup = Group(title: "DEBUG", selectors: [ BoolSelector(key: Keys.isDebugMode.rawValue, title: "デバッグモード") ]) let featureGroup = Group(title: "FEATURE", selectors: [ BoolSelector(key: Keys.featureFlagA.rawValue, title: "新機能Aを有効化"), BoolSelector(key: Keys.featureFlagB.rawValue, title: "新機能Bを有効化"), BoolSelector(key: Keys.featureFlagC.rawValue, title: "新機能Cを有効化"), ]) Group
  12. let app = App(name: "iOSDC Japan 2020", bundleID: "com.example.iosdc") let

    debugModeGroup = Group(title: "DEBUG", selectors: [ BoolSelector(key: Keys.isDebugMode.rawValue, title: "デバッグモード") ]) app.add(group: debugModeGroup) let apiGroup = Group(title: "API", selectors: [ BoolSelector(key: Keys.changeAPI.rawValue, title: "接続先APIを差し替える"), StringSelector(key: Keys.apiEndpoint.rawValue, title: "接続先API", values: [ "https://example.com/api", "https://example.com/sandbox-api", "https://example.com/staging-api", ]) ]) app.add(group: apiGroup) let featureGroup = Group(title: "FEATURE", selectors: [ BoolSelector(key: Keys.featureFlagA.rawValue, title: "新機能Aを有効化"), BoolSelector(key: Keys.featureFlagB.rawValue, title: "新機能Bを有効化"), BoolSelector(key: Keys.featureFlagC.rawValue, title: "新機能Cを有効化"), ]) app.add(group: featureGroup)
  13. let app = App(name: "iOSDC Japan 2020", bundleID: "com.example.iosdc") let

    debugModeGroup = Group(title: "DEBUG", selectors: [ BoolSelector(key: Keys.isDebugMode.rawValue, title: "デバッグモード") ]) app.add(group: debugModeGroup) let apiGroup = Group(title: "API", selectors: [ BoolSelector(key: Keys.changeAPI.rawValue, title: "接続先APIを差し替える"), StringSelector(key: Keys.apiEndpoint.rawValue, title: "接続先API", values: [ "https://example.com/api", "https://example.com/sandbox-api", "https://example.com/staging-api", ]) ]) app.add(group: apiGroup) let featureGroup = Group(title: "FEATURE", selectors: [ BoolSelector(key: Keys.featureFlagA.rawValue, title: "新機能Aを有効化"), BoolSelector(key: Keys.featureFlagB.rawValue, title: "新機能Bを有効化"), BoolSelector(key: Keys.featureFlagC.rawValue, title: "新機能Cを有効化"), ]) app.add(group: featureGroup)
  14. let app = App(name: "iOSDC Japan 2020", bundleID: "com.example.iosdc") let

    debugModeGroup = Group(title: "DEBUG", selectors: [ BoolSelector(key: Keys.isDebugMode.rawValue, title: "デバッグモード") ]) app.add(group: debugModeGroup) let apiGroup = Group(title: "API", selectors: [ BoolSelector(key: Keys.changeAPI.rawValue, title: "接続先APIを差し替える"), StringSelector(key: Keys.apiEndpoint.rawValue, title: "接続先API", values: [ "https://example.com/api", "https://example.com/sandbox-api", "https://example.com/staging-api", ]) ]) app.add(group: apiGroup) let featureGroup = Group(title: "FEATURE", selectors: [ BoolSelector(key: Keys.featureFlagA.rawValue, title: "新機能Aを有効化"), BoolSelector(key: Keys.featureFlagB.rawValue, title: "新機能Bを有効化"), BoolSelector(key: Keys.featureFlagC.rawValue, title: "新機能Cを有効化"), ]) app.add(group: featureGroup)
  15. let app = App(name: "iOSDC Japan 2020", bundleID: "com.example.iosdc") let

    debugModeGroup = Group(title: "DEBUG", selectors: [ BoolSelector(key: Keys.isDebugMode.rawValue, title: "デバッグモード") ]) app.add(group: debugModeGroup) let apiGroup = Group(title: "API", selectors: [ BoolSelector(key: Keys.changeAPI.rawValue, title: "接続先APIを差し替える"), StringSelector(key: Keys.apiEndpoint.rawValue, title: "接続先API", values: [ "https://example.com/api", "https://example.com/sandbox-api", "https://example.com/staging-api", ]) ]) app.add(group: apiGroup) let featureGroup = Group(title: "FEATURE", selectors: [ BoolSelector(key: Keys.featureFlagA.rawValue, title: "新機能Aを有効化"), BoolSelector(key: Keys.featureFlagB.rawValue, title: "新機能Bを有効化"), BoolSelector(key: Keys.featureFlagC.rawValue, title: "新機能Cを有効化"), ]) app.add(group: featureGroup)
  16. アジェンダ • デバッグメニューとは • 背景 • 仕組み • 実装方法 •

    デバッグメニューアプリ作りのコツ • CI時のコツ • メリットとデメリット
  17. ".app" の作り方 ビルド方法 lane :build_app_file do xcodebuild( scheme: 'Chusha', build:

    true, sdk: 'iphonesimulator', derivedDataPath: 'build' ) end Fastfile Bitrise OR
  18. ".app" の作り方 GitHub Releasesにuploadする set -eu go get -u github.com/tcnksm/ghr

    version=0.0.1 name=chusha-${version}.tar.gz mkdir -p releases cp -r build/Build/Products/Debug-iphonesimulator/Chusha.app releases/Chucha.app tar zcvf $name releases body="ADHOC: ${ADHOC_INSTALL_PAGE_URL} <br>INHOUSE: ${INHOUSE_INSTALL_PAGE_URL}" echo $ADHOC_INSTALL_PAGE_URL echo $body ghr -delete -n $version -b "${body}" $version $name
  19. ".app" の作り方 GitHub Releasesにuploadする set -eu go get -u github.com/tcnksm/ghr

    version=0.0.1 name=chusha-${version}.tar.gz mkdir -p releases cp -r build/Build/Products/Debug-iphonesimulator/Chusha.app releases/Chucha.app tar zcvf $name releases body="ADHOC: ${ADHOC_INSTALL_PAGE_URL} <br>INHOUSE: ${INHOUSE_INSTALL_PAGE_URL}" echo $ADHOC_INSTALL_PAGE_URL echo $body ghr -delete -n $version -b "${body}" $version $name
  20. ".app" の作り方 GitHub Releasesにuploadする set -eu go get -u github.com/tcnksm/ghr

    version=0.0.1 name=chusha-${version}.tar.gz mkdir -p releases cp -r build/Build/Products/Debug-iphonesimulator/Chusha.app releases/Chucha.app tar zcvf $name releases body="ADHOC: ${ADHOC_INSTALL_PAGE_URL} <br>INHOUSE: ${INHOUSE_INSTALL_PAGE_URL}" echo $ADHOC_INSTALL_PAGE_URL echo $body ghr -delete -n $version -b "${body}" $version $name
  21. アジェンダ • デバッグメニューとは • 背景 • 仕組み • 実装方法 •

    デバッグメニューアプリ作りのコツ • CI時のコツ • メリットとデメリット
  22. メリット • 1つのアプリで複数のアプリにデバッグ情報を注入できる • 起動した時点でデバッグ情報が注入されている ‣ 初回起動時になにかしたい時に便利 • App Storeに公開されているアプリでも使える

    • #if DEBUG の利用が減らせる ※登壇後追記:収録後の2020年9月11日にレビューガイドラインが更新され、下記の通りガイドラインの明確化されました。 2.3.1: Don’t include any hidden, dormant, or undocumented features in your app; your app’s functionality should be clear to end users and App Review. このため、App Storeに公開されるバージョンでもChushaが利用できると、リジェクトされる可能性があります。あらかじめご了承ください。