計測フレームワークのSwift Package Manager導入への道のり

計測フレームワークのSwift Package Manager導入への道のり

はじめに

こんにちは、計測プラットフォーム開発本部iOSブロックの中岡です。普段はZOZOMAT/ZOZOGLASSの運用・保守や計測技術を使った新規事業の開発をしています。

目次

計測フレームワークとは

私たちのチームは、ZOZOMAT/ZOZOGLASSの機能を開発し、それらをライブラリとしてZOZOTOWN iOSチームに提供しています。このライブラリのことを私たちは計測フレームワークと呼んでいます。そしてこのライブラリの提供方法として今まではCocoaPodsを利用していました。元々はCarthageを利用していたのですが、Apple silicon導入に伴いCocoaPodsへ移行しています。そちらの経緯は以下の記事とMeetupのアーカイブをご参照ください。

techblog.zozo.com

youtu.be

speakerdeck.com

Swift Package Managerへの移行の経緯

基本的にCocoaPodsに移行してからは開発体験などに問題はありませんでした。しかし、Appleから発表されたPrivacy Manifestに対応するため、依存ライブラリのいくつかを最新に更新する必要があり、そこでいくつかの問題に直面しました。以下はZOZOTOWN iOSの依存関係の一部です。

ZOZOTOWN iOSの依存関係

この中で以下のライブラリがPrivacy Manifestの対象1でした。

Lottieに関しては特に問題なくCocoaPodsで最新版に更新できました。しかし、BoringSSLとnanopbはCocoaPodsで最新版にするには一筋縄ではいきませんでした。まずBoringSSLに関しては、依存しているgrpc-swiftの最新版がCocoaPodsでのサポートはされておらず、Swift Package Manager(以下SPM)のみとなっていました。

github.com

nanopbに関しては、依存しているARCoreはCocoaPodsをサポートしています。しかし、CocoaPodsを使用してARCoreの最新版を導入すると、問題が発生しました。本来インストールしているOpenCVではなく、ARCoreが内部で使用しているOpenCVとZOZOGLASSがリンクし、クラッシュすることがわかりました。この問題は、SPMを利用してARCoreを導入することで解消されたことが確認されており、現在はその詳しい原因を調査中です。

これらの問題から、計測フレームワークをSPMへ移行することにしました。また合わせて、ZOZOTOWN iOSは共有の依存としてLottieやnanopb(Firebaseの依存)を持っているので、これらも同時にSPMへ移行しました。

Swift Package Managerへの移行

基本的には、podspecに記載されているdependencyやsource_fileをPackage.swiftに移行するだけです。以下の公式ドキュメントを参考に作業を進めました。

github.com

developer.apple.com

移行前のpodspecの一部

Pod::Spec.new do |spec|
  spec.name = "ZOZOMAT"
  # 省略

  spec.source_files = "Sources/ZOZOMAT/**/*.swift"

  spec.resource_bundles = { "ZozomatResources" => [
    "Sources/ZOZOMAT/Resources/**/*.xib",
    # 省略
  ] }

  spec.dependency "SwiftGRPC", "0.11.0"
  spec.dependency "lottie-ios", "3.2.3"

  # 省略
  }
end

移行後のPackage.swiftの一部

import PackageDescription

let package = Package(
    name: "ZOZOMAT",
    defaultLocalization: "ja",
    platforms: [
        .iOS("15.5.0")
    ],
    products: [
        .library(
            name: "ZOZOMAT",
            targets: ["ZOZOMAT"]
        ),
    ],
    dependencies: [
      .package(url: "https://github.com/grpc/grpc-swift.git", .upToNextMajor(from: "1.21.1")),
      .package(url: "https://github.com/airbnb/lottie-spm", .upToNextMajor(from: "4.4.0")),
      // 省略
    ],
    targets: [
        .target(
            name: "ZOZOMAT",
            dependencies: [
              .product(name: "Lottie", package: "lottie-spm"),
              .product(name: "GRPC", package: "grpc-swift"),
              // 省略
            ],
            path: "Sources/ZOZOMAT", // source_fileに対応するディレクトリを指定
            resources: [
                .process("Resources")
            ],
        )
    ]
)

移行作業でハマったこと

そして作業を進めていく中で以下の2つのハマりポイントがありました。

  1. Objective-Cが含まれているSwift Packageでのバンドルリソースへのアクセス方法
  2. 同じソースコードを複数のターゲットで使用できない

まず1に関して、ZOZOMATの3D表示の機能はC++とObjective-Cで書かれており3、それらは別のライブラリとして管理されています。そしてこのライブラリはシェーダーコードなどのリソースを持っています。Objective-CからSwift PackageのバンドルにアクセスするにはSWIFTPM_MODULE_BUNDLEというマクロを使用します4。基本的にはSwiftのBundle.moduleと同じように動作します。以下のPackage.swiftの場合、リソースバンドルはSampleObjc-Package_SampleObjc-Target.bundleという名前になります。

import PackageDescription

let package = Package(
    name: "SampleObjc-Package",
    products: [
        .library(
            name: "SampleObjc-Target",
            targets: ["SampleObjc-Target"]),
    ],
    targets: [
        .target(
            name: "SampleObjc-Target",
            path: "Sources/SampleObjc",
            resources: [
                .process("Resources")
            ]
        ),
    ]
)

しかし、Objective-CからSWIFTPM_MODULE_BUNDLEを使いアクセスしようとすると、以下のエラーのようなエラーが出て、クラッシュします。これは実際のバンドル名がSampleObjc-Package_SampleObjc-Target.bundleなのに、SampleObjc_Package_SampleObjc_Target.bundleにアクセスしているために発生します。これを避けるためにObjective-CのSwift Packageでは名前に-を含めないようにする必要があります。

*** Terminating app due to uncaught exception 'SwiftPMResourcesAccessor', reason: 'unable to find bundle named SampleObjc_Package_SampleObjc_Target'

次に2の「同じソースコードを複数のターゲットで使用できない」に関してです。ZOZOMATは一部の機能をZOZOTOWN iOSとZOZOMATの計測機能のみを持つデモアプリで処理を分岐させるためにActive Compilation Conditionsを使っています。podspecに以下のようにフラグを設定しZOZOTOWNに提供しており、デモアプリの場合はpod install時にpost_installでそのフラグを書き換えていました。

ZOZOMATのpodspec

 # ZOZOTOWN用フラグを設定
spec.pod_target_xcconfig = {
  "SWIFT_ACTIVE_COMPILATION_CONDITIONS" => "ZOZOMAT_RELEASE",
}

ZOZOMATのローカルにあるデモアプリ用のPodfile

# デモアプリ用のフラグを設定
def set_demo_mode(pi)
  pi.pods_project.targets.each do |t|
    t.build_configurations.each do |bc|
      if t.name == "ZOZOMAT"
          bc.build_settings["SWIFT_ACTIVE_COMPILATION_CONDITIONS"] = "ZOZOMAT_DEMO"
      end
    end
  end
end

post_install do |pi|
  set_demo_mode(pi)
end

これは元々Carthageを使っていた時に、デモアプリ用とZOZOTOWN用の2つのXcodeターゲットを用意し、フラグで処理を分岐させるという方法をとっていたためです。これと同じことを実現するために以下のように共通のソースコードを持つ2つのターゲットを定義し、それぞれに別のフラグを設定しようと考えましたが、SPMでは同じソースコードを複数のターゲットに含めることができませんでした。以下のようにPackage.swiftを定義しそれぞれのターゲットでswiftSettingを設定しようとするとエラーが出ます。

そのため、現在は一時的な対応としてデモアプリを動かす際はswiftSettingを書き換えて作業を行うという方法をとっています。将来的にはライブラリ内にこのような分岐を持つことは本来望ましくないので、リファクタリングをする予定です。

target 'ZOZOMATDemo' has overlapping sources: /Users/xxxxxx/SamplePackage/Sources/ZOZOMAT/Sample.swift
import PackageDescription

let package = Package(
    name: "ZOZOMAT",
    products: [
        .library(
            name: "ZOZOMAT",
            targets: ["ZOZOMAT"]),
        .library(
            name: "ZOZOMATDemo",
            targets: ["ZOZOMATDemo"]),
    ],
    targets: [
        .target(
            name: "ZOZOMAT",
            path: "Sources/ZOZOMAT",
            swiftSettings: [
                .define("ZOZOMAT_RELEASE")
            ]
        ),

        // 以下のようにすることはできない
        .target(
            name: "ZOZOMATDemo",
            path: "Sources/ZOZOMAT",
            swiftSettings: [
                .define("ZOZOMAT_DEMO")
            ]
        ),
    ]
)

まとめ

本記事では、計測フレームワークをSPMへ移行する際の経緯と移行作業でハマったポイントについて紹介しました。SPMへの移行により、依存ライブラリの更新ができPrivacyManifestの対応ができましたが、移行によって新たに発生した問題もあります。

  • ブランチ切り替えの際に毎回Package resolveが走り時間がかかる
  • ZOZOTOWN iOSはCocoaPodsとSPMの混在状態となっている
  • ZOZOMATのデモアプリを動かす際に手動でswiftSettingを書き換える必要がある

今後はこれらの問題を解決し、より良い開発体験になるように改善していきたいと考えています。

ZOZOでは、一緒にサービスを作り上げてくれる方を募集中です。ご興味のある方は、以下のリンクからぜひご応募ください。

corp.zozo.com


  1. https://developer.apple.com/support/third-party-SDK-requirements/
  2. 5/1現在、最新のARCoreが依存しているnanopbはPrivacy Manifest対応されていないが将来的に対応される予定(issue
  3. https://techblog.zozo.com/entry/zozomat-cross-platform-3d
  4. https://developer.apple.com/videos/play/wwdc2020/10169/

5年ぶりの開催!「try! Swift Tokyo 2024」参加レポート

try! Swift 2024 Report

はじめに

こんにちは。DevRelブロックの@wirohaです。2024年3月22日〜24日に「try! Swift Tokyo 2024」が開催されました。ZOZOはGOLDスポンサー・DIVERSITY & INCLUSIONスポンサーとして協賛し、ブースを出展しましたので現地のレポートをお届けします!

続きを読む

チームで挑む、ZOZOTOWN iOSでのSwiftUI導入実践話

チームで挑む、ZOZOTOWN iOSでのSwiftUI導入実践話

こんにちは、ZOZOTOWN開発1部iOSブロックの荻野です(@juginon)。

WWDC19でSwiftUIが発表されてから今年で5年になりますが、みなさんの携わっているプロジェクトではSwiftUIを使っていますか。ZOZOTOWN iOSチームでは、2023年11月にリリースしたアイテムレビュー機能1へ向けSwiftUIを積極的に導入する方針を定め、新規画面及びUI要素ではSwiftUIでの実装に取り組みました。

巨大なプロジェクトであるZOZOTOWN iOSにSwiftUIをどのように導入していったのか? 本記事では、実際にプロダクトコードに導入したことで見えた問題点、そこで得た知見を踏まえた上でのSwiftUIの導入方針についてご紹介します。

続きを読む

【イベントレポート】After iOSDC Japan 2023を開催しました!

After iOSDC Japan 2023

はじめに

こんにちは。DevRelブロックの@wirohaです。9月11日にAfter iOSDC Japan 2023を開催しました。9月1日〜3日に開催されたiOSDC Japan 2023の協賛企業であるLINE株式会社、PayPay株式会社、株式会社ZOZO、ヤフー株式会社の4社合同での振り返りイベントです。

続きを読む

開発に手放せないツールと言えば〇〇!アンケートで振り返るiOSDC Japan 2023参加レポート

OGP

こんにちは、ZOZOTOWN開発本部ZOZOTOWNアプリ部のらぷらぷです。先日9/1から9/3までの3日間、iOSDC Japan 2023が開催されました。弊社からは3名が登壇し、プラチナスポンサーとして協賛してブースを構え、10名以上がスタッフメンバーとして参加しました。

technote.zozo.com

この記事では今年のiOSDCで登壇した3名の発表と弊社のスポンサーブースについてお伝えします。

続きを読む

WEARをリノベ!Objective-CからSwiftへのリプレイス戦略でも使えるスナップショットテスト

ogp

目次

はじめに

memoji

みなさん、こんにちは! 松井です。普段はWEAR iOSアプリ開発で、コードを書く筋肉をパンパンに鍛えています。WEARアプリは、長い歴史を持っており、まだまだObjective-Cで書かれたレガシーなコードも居座っているんです。そんな中、私たちは地道にリファクタリングを進めています。そうしたObjective-CからSwiftへのリプレイス戦略において、スナップショットテストを活用したお話をしたいと思います。

スナップショットテストと聞くと、一般的にはコードの修正前後でUIが変わってしまっていないかをチェックするためのテスト手法という印象が強いでしょう。しかし今回は単なる修正ではなく、大胆なリプレイスにおいて旧と新のViewController(以下、VC)を比較した際のUIリグレッション確認のためにスナップショットテストを活用しました。スナップショットテストの力を借りて、リプレイスは無事に完了! 0.5ptの微妙なズレや、他にもいくつかリグレッションを見つけることができ大助かりでした。

マイページ画面リプレイスに伴う課題

私たちが着手したのは、投稿したコーディネートや動画、持っているアイテムやお気に入りしたコンテンツを一元管理するマイページ画面です。Objective-C製のコードで動いており、テストが書かれておらず、そもそもテストを書きづらい設計になっていました。しかもこの画面、各項目をタブで仕分けしており、1つの画面内でタブを切り替えるごとにUIがガラリと変わります。ユーザのプロフィールも表示しているので、プロフィール情報によってもUIが変化するんです。確認パターンが多すぎて、まさに開発者の強敵! 確認に工数がかかり、人的なミスも誘発しやすいです。ならばここは、スナップショットテストで対抗しましょう! スナップショットテストの使い方としては、まずObjective-Cによって書かれた旧VCでリファレンス画像を撮ります。それを元にSwiftへ生まれ変わった新VCが旧VCの見た目を再現できているかをテストすることで、解決を図ります。

mypage

使用したライブラリ

ライブラリはPoint-Freeのswift-snapshot-testingを選択しました。このライブラリは、デバイスごとのプリセットが用意されているという点が優れています。後述しますが、これによりデバイスのサイズを指定しなくても良くなり、複数のデバイスのテストを一度に行うことができるんです。

Objective-Cでリファレンス、Swiftでテスト

さて、Objective-CとSwiftでの見た目の違いを検証する際の、具体的なコードをお見せします。

@MainActor
final class MypageViewControllerTest: XCTestCase {
    // リファレンス画像撮影モードを切り替える
    private let isRecord: Bool = true

    func testコーディネートタブ_投稿1件() async throws {
        let vc: UIViewController
        if isRecord {
            // VCを作成して返すメソッドは別途作成する必要があります。
            vc = makeOldMypageViewController(tabType: .coordinate, dataCount: 1)
        } else {
            vc = makeNewMypageViewController(tabType: .coordinate, dataCount: 1)
        }
        snapshot(vc: vc)
    }

    private func snapshot(vc: UIViewController) {
        // テスト対象のViewControllerを表示
        UIApplication.shared.firstKeyWindow?.rootViewController = vc

        // スナップショットテスト実行部分
        // .imageHEICに関しては後述します。
        assertSnapshots(matching: vc, as: [.imageHEIC], record: isRecord, testName: "testコーディネートタブ_投稿1件")
    }
}

isRecord変数を定義し、このフラグを使うことでObjective-CとSwift、どちらのVCをテスト対象とするかを切り替えています。実際にスナップショットテストを実行するコードは、snapshot(vc: UIViewController)メソッドの中に閉じ込めています。

上記のテストコードを実行すると、isRecordがtrueの時は旧VCのマイページ画面でリファレンス画像が生成されます。isRecordをfalseにして実行すると、リファレンス画像と新VCのマイページ画面を比較するテストが走ります。リファレンス画像どおりの見た目になっていたらテスト成功となります。失敗した場合は、失敗画像が生成されるので、リファレンス画像との差分を見比べて新VCのコードを修正します。

普通にテストを実行するだけならここまでの話で十分なのですが、swift-snapshot-testingには、強力な機能がほかにも備わっています。次のセクションからは、私たちが実際に使ってみて「これは便利だな」と感じたTipsをいくつか紹介します。

リファレンス画像のファイルサイズを小さく

ここでは前節で省略した、assertSnapshotsの引数に指定した.imageHEICについて説明します。

リファレンス画像が増えたり、サムネイル画像が含まれていたりすると、どうしてもファイルサイズが大きくなってしまいます。しかもGitで管理したい場合、なおさらファイルサイズが気掛かりですね。ライブラリのREADMEを見ると多数の拡張ライブラリが紹介されており、その中にSnapshotTestingHEICというHEIC形式でリファレンス画像を出力してくれる拡張ライブラリを発見しました。swift-snapshot-testingはPNG形式でリファレンス画像を出力しますが、PNGよりHEICのほうがファイルサイズを小さくできます。こちらを採用した結果、ファイルサイズを1/4〜1/3くらいまで落とすことができました。 filesize

上のコードに出てきた.imageHEICというキーワードは、このSnapshotTestingHEICが提供している機能だったというわけです。拡張ライブラリは、他にもいくつか紹介されています。プロジェクトのニーズに合う拡張機能がないか確認してみると良いかもしれません。

デバイスも言語も一気にテスト

WEARでは、日本語、英語、中国語(簡体字・繁体字)と複数の言語をサポートしています。そのため、言語が変わった時の表示と、複数のデバイスでの表示も確認しておきたいですね。スナップショットテストを使えばこうした色んな条件でのテストも楽チンです。言語の自動化はTestPlan、デバイスはswift-snapshot-testingが提供している各端末サイズのプリセットを使えば可能です。

複数言語のテスト自動化

まず、XcodeでTestPlanを新規作成します。TestPlanのConfigurations > Application Languageでテスト対象の言語を設定するだけです。あとはXcodeが自動的に、選択した言語環境でテストを回してくれます。

testplan

複数デバイスを一気にテストする方法

次に複数のデバイスを1度にテストするための、管理と実施方法について説明します。今回swift-snapshot-testingを採用した決め手となった、プリセットの出番です!

まずは、テストしたいデバイスをまとめておくためのSnapshotConfigというenumを作ります。これにはViewImageConfigを使います。これこそがswift-snapshot-testingが提供する便利な機能で、それぞれのデバイスに対するプリセット情報を持っています。

import Foundation
import SnapshotTesting

enum SnapshotConfig: CaseIterable {
    case iPhone8
    case iPhone13
    case iPhone13ProMax
    case iPad9_7

    func device() -> ViewImageConfig {
        switch self {
        case .iPhone8:
            return ViewImageConfig.iPhone8
        case .iPhone13:
            return ViewImageConfig.iPhone13
        case .iPhone13ProMax:
            return ViewImageConfig.iPhone13ProMax
        case .iPad9_7:
            return ViewImageConfig.iPad9_7
        }
    }
}

これで準備完了です。あとはテストケースでSnapshotConfig.allCasesを回すだけ。一度のテスト実行で、複数のデバイスのテストが可能です。

@MainActor
final class MypageViewControllerTest: XCTestCase {
    private let isRecord: Bool = true

    func testコーディネートタブ_投稿1件() async throws {
        let stubUser = makeStubUser()
        WRAccountManager.sharedInstance()?.setValue(stubUser, forKey: "user")

        SnapshotConfig.allCases.forEach {
            let vc: UIViewController
            if isRecord {
                vc = makeOldMypageViewController(tabType: .coordinate, dataCount: 1)
            } else {
                vc = makeNewMypageViewController(tabType: .coordinate, dataCount: 1)
            }
            snapshot(vc: vc, config: $0)
        }
    }

    private func snapshot(vc: UIViewController, config: SnapshotConfig) {
        UIApplication.shared.firstKeyWindow?.rootViewController = vc

        let suffix = "\(config)-\(Locale.preferredLanguages.first ?? "")"

        assertSnapshots(matching: vc, as: [.imageHEIC(on: config.device)], record: isRecord, testName: "testコーディネートタブ_投稿1件" + suffix)
    }
}

ここで紹介した実装方法は、メルペイiOSチームのスナップショットテストを効率化した話を参考にしました。

いにしえVCのためのスタブデータの用意

さいごに、あなたのいにしえVCでも使えるかもしれないスタブデータの用意の仕方をご紹介します。

スタブデータの作成、今回これがなかなかの難敵でした。マイページ画面はユーザ情報によりUIが変化します。テストケースごとにこの情報を変えたいのですが、お相手は、Objective-Cで書かれたダシの効いたコード。ユーザ情報はAccountManagerクラスでuserプロパティとして保持されており、userプロパティはreadonlyになっていることから、スタブデータのセットが難しい状況でした。AccountManagerクラス自体の改修は、今回のリプレイスに関係のないコードにまで連鎖的に影響を及ぼす可能性があり、そう簡単には手出しできません。そんな時、大活躍したのがKey-Value Coding(KVC)を使う方法です。KVCはNSObjectが標準で提供している機能で、これを使えば、例えプロパティがreadonlyだったとしても、Objective-Cの変数の値をいじったり取り出したりできます。

具体的な使い方は以下のような感じです。

func testヘッダー_性別のみ表示() async throws {
    let stubUser: User = makeStubUser()
    stubUser.sexName = "WOMAN"
    stubUser.height = nil
    AccountManager.sharedInstance()?.setValue(stubuser, forKey: "user")

    // 以下、スナップショットテスト実行コード 
}

まずスタブのユーザ情報を持ったstubUserを作成します。上記の例では性別を女性、身長を未設定にしています。このstubUserをAccountManagerのuserプロパティにsetValueメソッドを使ってセットすることで、テストケースごとにユーザ情報をコントロールすることが可能になります。とても便利な機能ですが、あくまでNSObjectが標準で提供するものですので型チェックをスルーしてしまうところが落とし穴です。プロダクトコードでの使用は避けたほうが良いですが、今回はテストコードだったため使用しています。

おわりに

Swiftに生まれ変わったマイページ画面がリリースされ、Objective-C製のマイページにさよならするとき、リグレッションの役目を終えたスナップショットテストも削除しました。役目を全うしたスナップショットテスト、おつかれさまでした! 今後も大掛かりなリプレイスをする際に活躍してくれることでしょう。この記事が、みなさんのプロジェクトでのリプレイス戦略にも何かのヒントになれば嬉しい限りです。より良いソフトウェア開発をこれからも進めていきましょう!

ZOZOでは一緒に楽しく働くエンジニアを絶賛募集中です。ご興味のある方は下記リンクからぜひご応募ください。

corp.zozo.com

【イベントレポート】ZOZO Tech Meetup - iOS/Androidを開催しました!

レポート:ZOZO Tech Meetup - iOS/Android

はじめに

こんにちは。DevRelブロックの@wirohaです。7月11日にZOZO Tech Meetup - iOS/Androidを開催しました。ZOZOのiOSエンジニアとAndroidエンジニアがそれぞれの技術領域にフォーカスして紹介するイベントです。オンラインとオフラインのハイブリッドで開催しました。

オープニングの様子

続きを読む

【イベントレポート】「WWDC23 報告会 at LINE, ZOZO, ヤフー」を開催しました!

WWDC23報告会

はじめに

こんにちは。DevRelブロックの@wirohaです。6月27日に「WWDC23 報告会 at LINE, ZOZO, ヤフー」を開催しました。WWDCに参加した各社のエンジニアが新しく発表された技術や得た知見・情報などを共有するイベントです。今年はオンラインと一部オフラインのハイブリッドで開催しました。

会場全景

登壇内容まとめ

3社の社員によるLTとパネルディスカッションを行い、その後は交流会で盛り上がりました。なお本イベントはAppleがNDAを締結した開発者にのみ公表している情報を取り扱っており、参加はApple Developer Programに加入している方に限定させていただきました。本レポートもLTの詳細は割愛し、雰囲気をお伝えできればと思います。

コンテンツ 登壇者
What’s new in image processing たなたつ (田中 達也) ◆ヤフー
Hello Object Capture for iOS! 森口 友也 ◆ZOZO
Animate SF Symbols 羽柴 彩月 ◆LINE
Whatʼs new in privacy 2023 大塚 達也 ◆ヤフー
The New Potential of Widgets 山田 楓也 ◆ZOZO
What’s new in Swift 5.9 Hiraki ◆LINE
Panel Discussion 早石 明浩 ◆LINE
冨田 悠斗 ◆ヤフー
永井 崇大 ◆ZOZO
まつじ (松本淳之介) ◆LINE
交流会

発表風景

ヤフーの田中さま

ZOZOの森口

LINEの羽柴さま

ヤフーの大塚さま

ZOZOの山田

LINEのHirakiさま

Panel Discussion

挙手をしながらパネルディスカッションを進行

乾杯をしてカジュアルな雰囲気でパネルディスカッションがはじまりました。随時質問を挟み会場の皆さんに手をあげていただき、双方向のコミュニケーションを取りながら楽しく進行しました。

最も印象に残った発表はApple Vision Pro

最も印象に残った発表は「Apple Vision Pro」で満場一致でした。久しぶりの「One more thing...」に現地会場は大興奮で一体感があったそうです。

興味があったセッションはUIKitやARKitなど各々の好きな分野を熱く語っていました。試したい機能やプロジェクトで実装したいことについては、普段の業務知識や関心があるからこその発想があげられていました。

前日の現地での様子を紹介

パネリストの3人より前日・当日のタイムラインを写真で共有いただきました。現地に参加した方は前日からノベルティの受取や著名な方との写真撮影をしており、イベントを楽しむ様子が伝わってきます。日本にいた方はヤフー紀尾井町オフィスのLODGEにて行われたリアルタイム視聴イベント「Extended Tokyo - WWDC 2023」に参加していました。こちらの様子はレポート記事がありますのでこちらもぜひご覧ください!

techblog.zozo.com

交流会

パネルディスカッションの後、オフライン会場にて交流会を実施しました。Apple JapanからTechnology Evangelistの豊田さまにご参加いただき、参加者からのさまざまな質問に回答いただきました。登壇したみなさまもリラックスした様子で交流を楽しんでいました。

Apple Japanの豊田さま

最後に

みなさまご参加ありがとうございました。WWDCの報告会は毎年の恒例イベントです。また来年も開催できることを楽しみにしています!

ZOZOでは一緒にサービスを作り上げてくれる仲間を募集中です。ご興味のある方は以下のリンクからぜひご応募ください。

hrmos.co

Appleが提供する濃密な5日間! - WWDC23参加レポート

opg

こんにちは。FAANSブロックiOSチームの加藤です。

masho

日本時間の6月6日から10日にかけてWWDC23が開催されました。

WWDC23では、空間コンピュータ「Apple Vision Pro」を始め、iOS 17、SwiftDataなどワクワクする発表が目白押しでした。

今年は去年と同様に、抽選に当選すれば現地で開催されるApple Parkのパブリックビューイングにも参加できました。ZOZOからは2名が当選して、現地に赴きました!

本記事では、WWDC23におけるZOZOのiOSアプリ開発メンバーの取り組みについてご紹介します。また、オフライン参加メンバーによる現地レポートや、ラボ、セッションに参加して得られた知識も可能な範囲で公開します。ぜひ最後までご覧ください。

WWDCについて

WWDC(Worldwide Developers Conference)は、Appleが年に1度開催している開発者向けのカンファレンスです。OSのアップデートをはじめ、開発環境周りの新機能が発表されます。今年は昨年に続いてハイブリッド開催であり、ZOZOの当選したメンバーは業務の一環として現地参加しました。また、オンラインで参加したメンバーは、セッションやラボ、アクティビティに参加しました。

現地で楽しむWWDC23

memoji_fuya_nagain

こんにちは、計測アプリ部の永井とフロントエンド部でWEARのiOSを担当している山田です。昨年に引き続き、今年もオフライン/オンライン同時開催となり、私たちは現地で参加してきました!

現地参加のスケジュールは以下の通りです。

日付 時間(Pacific Time) コンテンツ 場所
6月4日 3:00 PM Early Check-in Infinite Loop
6月5日 8:00 AM Check-in Apple Park Visitor Center
10:00 AM Keynote Apple Park
1:30 PM Platforms State of the Union Apple Park
3:00 PM Meet the Teams Apple Park - Caffè Macs
5:30 PM Apple Design Awards Apple Park

6月4日 - イベント前日

まず、私たちはEarly Check-inを済ませるため、Infinite Loopへ向かいました。Early Check-inを行うことで、イベント前日にネームカードや参加記念品をもらうことができます。列に並んで待っていると、Appleのスタッフが「ダブダブ!」「ディーシー!」のコールで盛り上げ、イベント前日から既に気合が入っていました。

0604_inifiniteloop

Early Check-inを済ませた後、参加記念品をいただきました。今年は、トートバック、帽子、水筒、ピンバッジでした。ピンバッジの種類は、Mac OSのレインボーカーソル、アップルのロゴ、絵文字など様々でした。絵文字は人によって異なっていました。

0604_novelty

Infinite Loopは多くの人で賑わっており、参加者同士がドリンクや軽食を楽しみながら交流していました。広場の芝生には椅子とパラソルが配置され、くつろぎながらおしゃべりできる雰囲気が漂っていました。

0604_square

会場では、DJが高いBPMの曲で盛り上げたり、ビッグスケールのジェンガやパズルゲームが行われるなど、非日常的な雰囲気が広がっていました。さらに、そこでAppleの関係者と写真を撮るなど、WWDCのムービーでしか見たことのないような楽しい時間を過ごすことができました。

0604_dj

イベント前日はここで終了です。さあ、明日はどんな日になるのか。

0604_nagain_fuya

6月5日 - イベント当日

イベント当日。私たちは、チェックインが始まる時間より1時間も前にVisitor Centerへと向かいました。それは、Keynoteを最前列で視聴するため、そして歴史的瞬間を誰よりも前で目撃するためです。しかし、驚くべきことに、そんな私たちよりもさらに早くに来て、チェックインの待機列に並んでいる猛者が20名ほどいました。

待機列に並び、重いまぶたを擦りながら待っているとスタッフがコーヒーと朝食を配ってくれました。前日に引き続き、デベロッパーに対する素晴らしいホスピタリティに感動しました。

0605_coffee

待機列に並ぶデベロッパーたちと今年はどんな発表がありそうかと話しているうちに、チェックインの時間となりました。

はやる気持ちを抑えながらチェックインを済ませ、道を進んでいくと、そこには象徴的なドーナツ型のオフィスがありました。近未来的なデザインのオフィスと、それを取り囲む大自然が、不思議と調和していて芸術的でした。

0605_office

おっと、気を奪われてはいけません。そこからは脇目も振らず、パブリックビューイング会場を目指し、無事に最前列の席を確保できました。早起きしたかいがありました。

今年のパブリックビューイング会場には、巨大な屋根が建て付けられていました。去年の参加メンバーからは日差しが照りつける会場だったと聞いていましたが、今年は去年を踏まえた改善がしっかりとされていました。

0605_venue

パブリックビューイング

席を確保したのち、Caffè Macsで朝食を食べていると、あっという間に時間は過ぎて、Keynoteの時間となりました。

去年と同じく、Keynoteの幕開けとともにティム・クックとクレイグ・フェデリギが壇上に上がりました。最前列だからこそ、ティムとクレイグの存在がすぐそこに感じられました。

0605_keynote

Keynote本編では、NameDropやStandByの発表、小島秀夫氏の登場など様々な驚きがあり、その度に会場の聴衆からは歓声が上がりました。その中でも、ひときわ聴衆を熱狂させたのはやはり、「One more thing …」のお馴染みのフレーズとともに発表されたvisionOSの登場でした。

Keynoteに続くPlatforms State of the UnionはCaffè Macsで、WWDCのTシャツを着たAppleのスタッフに交じって視聴しました。Swift macrosやSwiftDataなどデベロッパーとしてワクワクするアップデートが多く、会場からも喜びの声が上がったり、拍手が起きたりしていました。

0605_platforms

Meet the Teams

パブリックビューイングの時間が終わると、現地ではMeet the Teamsという、Appleのエンジニアやデザイナーと直接話せるイベントが催されました。

会場のスクリーンには、どのエリアに何のチームがいるのかのマップが映し出されており、興味のあるエリアに行って自由に話しかけることができました。

0605_meet_01.JPG

私たちはSpatial Computing、SwiftUI、Design、Developer Toolsなどのエリアに行って、日頃気になっていたことや今年の発表について根掘り葉掘り聞きました。その中でも特に印象的だったのはDesignのエリアです。Appleのデザイナーに自分たちのアプリを見てもらい、目から鱗が落ちるフィードバックを受けられました。そして、そのフィードバックをチームに共有して、実際に改善する動きまで繋げられました。

0605_meet_02.jpg

ZOZO×WWDC23オンライン

現地参加した2名以外のほとんどのメンバーがWWDC23にオンラインで参加しました。ZOZOでは、WWDCの開催期間中、現地に合わせて日本時間2:00〜11:00で勤務するメンバーや、通常の勤務時間で公開されているセッションの映像を視聴するメンバーもいました。

キャッチアップした情報を共有するために、毎日1回、ビデオ通話によるミーティングを行っていました。また、視聴したセッションのサマリや、ラボやアクティビティで得た情報はMiroで管理していました。WWDC終了後には、多くの情報がMiroにまとめられて以下のようになっていました。 Miro

Miroを用いたやり方はWWDC21よりZOZOで実施しているもので、下記のWWDC21参加レポートに詳しく公開しているので、よろしければこちらもご覧ください。

techblog.zozo.com

Activities

WWDC23では、オンラインのActivitiesとして、Q&AやMeet the presenterが実施されました。Q&Aでは、対象のトピックについて気になったことをAppleのエンジニアやデザイナーにSlackを通して質問できます。またMeet the presenterでは、セッション後にセッションの担当者にSlackで質問できます。質問に対して担当者が丁寧に回答してくださるので、セッションについての理解が深まります。

私も「Machine learning open forum」のQ&Aや「Mix Swift and C++」のMeet the presenterで質問をさせていただきました! Q&A

また、オンラインのActivitiesとして「Trivia Time」が開催されました。Trivia Timeでは、参加者がWWDC23のセッション、開発ツール、Appleの歴史に関するトリビアクイズに挑戦しました。トリビアクイズでは、Xcodeの新機能に関することや、Appleの歴史に関するクイズが出題されました。クイズの参加者はSlackのスレッドで大いに盛り上がっていました! Trivia Time

Labs & Sessions

去年に引き続き、ZOZOメンバーがラボでAppleのスタッフにお聞きしたことやフィードバックを一部紹介します。また、セッション動画の中からZOZOメンバーとして気になったものも紹介します。

Swift open hours lab & Xcode open hours lab

tosh

ZOZOTOWN開発本部iOSブロックの小松(@tosh_3)です。自分はWWDCではLabに参加して、Appleのエンジニアと話すのが好きで、今年も2つのLabに参加してきました。今年参加したLabはSwift open hours labとXcode open hours labです。

Swift open hours labでは、CombineとAsync & Awaitの連携について相談しました。Combine内でasyncMapのようなその内部でawaitできるような高階関数を作成できないだろうかというのを既存のアイデアともに持っていきました。また、そこに付随しながら、iOS 17で追加されたAPIやそれらのバックポートに対する姿勢などについてAppleのエンジニアと話しました。

Xcode open hours labでは、XcodeのPreviewの機能について質問しました。ZOZOTOWNではメインターゲットとは別に、Preview専用のターゲットを作っています。というのも、メインターゲットでPreviewを行おうとすると必ず失敗するという問題があったためです。

Appleのエンジニアにこの問題について聞いたところ、どうもlinking周りに問題があるらしく、custom linker flagを設定しているか確認されました。これは、CocoaPods側で設定されるもののようで、これが多くなることでPreviewに対して悪影響を与えている可能性があるとのことでした。こういった問題に対して直接Appleのエンジニア回答をもらえるのもLabの魅力です。

今年のDemystifyセッション

lap

こんにちは、ZOZOTOWNブロックiOSチームの森口です。

私は毎年密かにDemystifyシリーズのセッションを楽しみにしています。

古くは2015年のMysteries of Auto Layout, Part 1に始まり、2021年にDemystify SwiftUIが発表され、2022年にはDemystify parallelization in Xcode buildsとDemystifyから始まるセッションが続いています。

これらのセッションはAppleの技術の仕組みをより深く理解するために視聴は欠かせません。

今年のWWDCではDemystify SwiftUI performanceというセッションが発表されました。SwiftUIはシンプルなレイアウトから複雑なレイアウトまで実装できますが、プロダクトに本番導入してみるとパフォーマンスの観点で無視できない問題に遭遇する場合があります。このセッションではSwiftUIにおけるパフォーマンス問題のいくつかの原因と対応について解説しています。

ZOZOTOWNは歴史が長く続く、多くのお客様に利用されているプロダクトです。コードのモダン化を安全に進めていくことが常に課題となる私たちにとって、このセッション内容から得た知見は今後の開発に大いに役立ちそうです。

Apple Vision Proの発表に寄せて

ikkou

ARやVRといったXR領域のリサーチや検証などを担当している創造開発ブロックの@ikkouです。頭はひとつしかないのにVRヘッドマウントディスプレイやARグラスはたくさん持っています。さて、世界で初めて家庭用として販売されたVRヘッドマウントディスプレイの「Oculus Rift DK1」がリリースされたのは10年前の2013年でした。それから10年が経ち、ついにAppleから最初のSpatial computerである「Apple Vision Pro」が発表されました。

WWDC20頃から“Apple Glass”なるものが出るぞ出るぞとまことしやかに噂されていましたが、WWDC21、WWDC22と“One more thing”もないまま年月を重ねていました。その一方で他社からは続々とVRヘッドマウントディスプレイやARグラスが登場し、期待ばかりが膨らむ状況が続いていました。

そんな中で満を持して発表されたのがApple Vision Proです。今年こそ発表される確度が高いということを意識してか、競合にあたるとも考えられるMeta社はMeta Quest 3をWWDC23の直前に急に発表しました。ARグラスのXREAL社(旧Nreal社)も自社製品との違いを存分にアピールしています。

今回の発表を受けて、iOS開発者界隈に限らず、XR開発者界隈も非常に沸いています。3,499ドルという価格(日本円にして約50万円)はMicrosoft社の複合現実HMDである「HoloLens 2」の¥422,180よりも高いです。3,299ドルで販売されている「Magic Leap 2」に近い価格帯です。決してお安いお買い物ではありませんが、アーリーアダプター気質のある開発者は間違いなく買うでしょう。もちろん私も買います。

開発者視点では、Unityの公式対応が発表されたことも大きな意味を持っています。Unityの公式対応により、生粋のiOSエンジニアだけではなく、Unityを使ったXRエンジニアもこれまでの資産を生かせることになります。早速ベータプログラムに申し込みました。

ところでAppleはSpatial computer、日本語では「空間コンピュータ」という言葉を用いていて、ARヘッドマウントディスプレイやVRヘッドマウントディスプレイといった言葉を用いていません。系譜としてはSpatial Computingという言葉を用いているMagic Leapに近い印象です。また、日本語では「没入」と訳されることの多いimmersiveというフレーズも用いています。ここには強い意思が感じられます。

そんなApple Vision Proに関連するセッションが複数用意されていたWWDC23でしたが、まず「Principles of spatial design」は必見です。あわせてアイトラッキングやハンドトラッキングに触れている「Design for spatial input」も欠かせません。空間コンピュータの名の通り、描画するのはiPhoneやiPadといった平面ではなく目の前にある空間そのものです。画面の絵作りや入力方法も大きく変わることを十分に理解する必要があります。

Apple Vision ProはUSでは来年初旬に、その他の国や地域では来年の後半より販売を開始とアナウンスされていますが、その対象に日本が入るかどうかは明示されていません。しかし、開発者向けのテスト施設である「Apple Vision Pro Developer Labs」をクパチーノ・ロンドン・ミュンヘン・上海・シンガポール、そして東京に開設することを発表しています。これは間違いなく日本でも発売されると言っても良いのではないでしょうか。

これからApple Vision ProのOSであるvisionOSの詳細が続々と発表されていくはずです。それらのリソースを頼りに日々“素振り”を続けていきたいところです。現場からは以上です!

まとめ

本記事では、WWDC23の参加レポートをお伝えしました。

今年のWWDCも現地・オンラインで楽しむことができ、参加したメンバーとしては充実した5日間だったと思います。また、Apple Vision Pro、iOS 17など数多くの発表があり、アプリ開発者に限らず、たくさんの人が進化や未来を感じたのではないでしょうか。ZOZOは、WWDC23に参加して得られた知見を業務に反映して、サービスの向上に努めていきます!

さいごに

ZOZOでは、一緒にサービスを作り上げてくれる仲間を募集中です。ご興味のある方は、以下のリンクからぜひご応募ください。

corp.zozo.com

【イベントレポート】Extended Tokyo - WWDC 2023を開催しました!

Extended Tokyo - WWDC 2023

はじめに

こんにちは。ZOZO DevRelブロックの@wirohaです。6月5日の深夜から6月6日にかけてExtended Tokyo - WWDC 2023を開催しました。

Extended Tokyoは、WWDCのメインセッション(Keynote)をさらに楽しむためのイベントです。今年もLINE株式会社、株式会社ZOZO、ヤフー株式会社の3社で主催しました。オフライン会場は2019年以来のヤフー紀尾井町オフィスにあるLODGEです。またオンライン会場は2021年ぶりにclusterのVR LODGEとハイブリッドで開催しました!

イベント内容まとめ

WWDCのKeynoteは日本時間で深夜2時からです。それに合わせて本イベントも23時30分と遅い時間からはじまりました。クイズ大会、LT大会で気分を高めた後、リアルタイムでKeynoteを視聴しました。

コンテンツ 登壇者
クイズ大会
LT1:Appleの進化を楽しむための歴史の授業 新妻 広康◆ヤフー
LT2:あなたの知らないWWDC現地参加の世界
〜Apple Parkへ行った僕が見た、新しいWWDC〜
荻野 隼◆ZOZO
LT3:WWDC「間」を復習しよう 平井 亨武◆LINE
LT4:メタバースプラットフォーム開発におけるSwiftUIの活用とTips 董 亜飛◆cluster
交流会
Keynote視聴

クイズ大会

WWDCや各社にちなんだクイズ大会でイベントスタートです! 正解した方にはノベルティが贈られました。

じゃんけんのようにクイズに回答

正解者へのプレゼント

現地中継

現地からは歓声も聞こえてきます

イベント中、何度か現地参加者とビデオ通話をつないで様子を伝えていただきました。とても明るく良い天気で、日本との気候の違いを感じますね。話しているとちょうど開場がはじまり、人がドッと動き出しました! 臨場感が伝わってきます!

Appleの進化を楽しむための歴史の授業

ヤフー株式会社 新妻さま

www.docswell.com

LT大会へと移り、新妻さまからはXcodeが生まれる前に遡って開発の歴史を紹介いただきました。AutoLayout、Swift、SwiftUIはアプリ開発の問題を解決する大きなソリューションですね。

あなたの知らないWWDC現地参加の世界 〜Apple Parkへ行った僕が見た、新しいWWDC〜

株式会社ZOZO 荻野

speakerdeck.com

ZOZOの荻野からは2022年のWWDCに現地参加した体験を時系列で発表しました。会議室やミニコンテンツ、現地で盛り上がった場面やトイレまで知れるのは面白かったです。今年もZOZOから現地に参加しているメンバーがおり、写真とメッセージを共有させていただきました!

WWDC「間」を復習しよう

LINE株式会社 平井さま

speakerdeck.com

平井さまからは1年でWWDCまでの間にあった出来事をご紹介いただきました。間に起きた出来事の中で、App Storeの価格の設定方法のアップデートとUIViewController.ViewLoadingについて詳細を解説いただきました。価格設定は悩ましいと共感の声が出ていました。

メタバースプラットフォーム開発におけるSwiftUIの活用とTips

クラスター株式会社 董さま

speakerdeck.com

董さまからはclusterでのSwiftUIの知見を発表いただきました。マルチプラットフォーム対応で毎週リリースしているのはすごいですね。タブインジケータや画像のズーム、Truncated Textの詳細な実装を解説いただきました。ARデバイスの発表に期待する声は他の発表でも出ていました。

交流会

Apple Park内の様子が気になるみなさま

Keynoteがはじまるまでは交流会を行いました。登壇者も発表が終わってホッとした様子でみなさんとお話を楽しんでいました。現地とも通話をつないで今年は何があるのか聞いたりしました。

Keynote視聴

ついにスタート!!

交流を楽しんでいるとあっという間にKeynoteの開始時刻となりました! 新しい情報には「おぉー」と声が上がったり笑いやどよめきが起きたり、みなさんと気持ちを共有できる楽しさを感じました。15インチMacBook Air、M2 Ultra、iOS 17など新しい情報が盛りだくさんでしたね。何よりApple Vision Proにはオフライン会場が沸きました! すごい、使ってみたいと早速感想を分かち合いました。

最後に

みなさま夜遅い時間にもかかわらずご参加ありがとうございました。WWDCの詳細をもっと知りたいと思った方はぜひ6月27日の「WWDC23 報告会 at LINE, ZOZO, ヤフー」にご参加ください。WWDCに参加した各社のエンジニアが、新しく発表された技術や得た知見、情報などを共有します。

line.connpass.com

ZOZOでは一緒にサービスを作り上げてくれるiOSエンジニアを募集中です。ご興味のある方は以下のリンクからぜひご応募ください。

hrmos.co

Swift 6に向けた準備:Strict Concurrency CheckingをTargeted設定にした際に発生した問題と解決方法

Strict-Concurrency-Checkingのタイトル画像

こんにちは、フロントエンド部の中島です。FAANSのiOSアプリの開発を行なっています。 FAANSの由来は「Fashion Advisors are Neighbors」です。「ショップスタッフの効率的な販売をサポートするショップスタッフ専用ツール」で2022年8月に正式ローンチしました。

はじめに

FAANS iOSチームではAPI通信においてSwift Concurrencyを利用しています。Swiftに限らず並行処理を扱う場合には実装次第でデータ競合を起こす恐れがあるのに対して、Swiftではデータ競合を防ぐ仕組みとしてActorが導入されています。そして、Actor間で扱うデータがデータ競合を起こさない型であるかコンパイラでチェックされます。Swift 6ではこのデータ競合のチェックにより既存のコードでコンパイルできなくなる可能性があります。Xcode 14ではSwift 6までの間に段階的な移行ができるようにStrict Concurrency Checkingでコンパイラのチェックレベルを指定できるようになりました。本記事ではFAANS iOSチームで実施したStrict Concurrency Checkingの対応と、その過程で得られた知見について紹介します。

続きを読む

ZOZOFIT iOSアプリ開発の全貌

ogp

はじめに

こんにちは、計測プラットフォーム開発本部アプリ部の中岡、永井、東原です。私たちのチームではZOZOMAT、ZOZOGLASSといった既存の計測機能の改善と、新規計測アプリの研究開発を担当しています。

その新規計測アプリとして、ZOZOFITというボディーマネジメントサービスを2022年の夏に米国でローンチしました。この記事では、ZOZOFITのiOSアプリを新規開発するにあたって、どのような技術要素を取り入れたかについてご紹介します。

目次

ZOZOFITとは

ZOZOFITは、ZOZOグループのZOZO Apparel USA, Inc.が提供するボディーマネジメントサービスであり米国でサービス提供をしています。

初代ZOZOSUITよりも大幅に計測精度を向上させたZOZOSUITを着用し、専用のスマートフォンアプリを利用することで手軽に3Dボディースキャンを行い、計測データをトラッキングできます。

計測可能な箇所は、肩幅、胸囲、腕周囲、ウエスト周囲、ヒップ周囲、太もも周囲、ふくらはぎ周囲の7箇所であり、体脂肪率も測定されます。計測データは下の画像のようにアプリ上で確認でき、過去のデータとの比較やグラフ表示が可能です。また、目標の管理機能によりそれぞれの計測部位について目標を設定でき、達成状況を確認できます。

ZOZOFIT iOS アプリ

図1:ZOZOFIT iOSアプリ

開発についてはグループ会社であるZOZO New Zealandと協業して進めています。プロジェクト全体の話は下記の記事がありますので、ぜひご覧ください。

technote.zozo.com

計測機能とその実装・統合

計測プラットフォーム開発本部アプリ部の永井です。ここでは、ZOZOFITの主要機能である計測機能の詳細と、その計測機能がiOSアプリへどのように実装・統合されているかについて説明します。

計測機能について

まずは、計測機能がどのようなものかをユーザー視点で説明していきます。

計測は、スーツを着用したユーザーの全身をスマートフォンの背面カメラで360度撮影することによって行われます。以下の図は、アプリ内のチュートリアルで使われているものです。

計測方法

図2:計測方法

このように計測時、ユーザーはスマートフォンをスタンドに立てかけ、そこから2mほど離れた場所に立つ必要があります。そして、その場で体を0時から12時まで回転させながら、合計12枚の写真を撮影します。

計測の最中、ユーザーには背面カメラが向けられていて画面を見ることができないため、計測を進めるための案内はすべて音声により行われます。

そうして案内に沿って計測を完了させると、アプリ上で全身の3Dモデルと計測データを見ることできます。以下の図は実際のアプリ画面です。

計測結果

図3:計測結果

このように自身の身体の気になる部位について、いろいろな角度から3Dモデルを見たり、計測データの変化をグラフで追ったりできます。

計測機能の実装・統合について

計測機能の実装・統合の説明にあたって、先に計測機能のアルゴリズムを紹介します。詳細は伏せますが、簡略化すると以下のようになります。

  1. ZOZOSUITを着用したユーザーを360度、12枚の写真として撮影
    • ユーザーとスマートフォンとの距離やユーザーの身体の回転具合などに問題がないかをチェックする
  2. 撮影した写真を画像処理
    • スーツ全体に施されたドットマーカーのパターン認識
    • ユーザーの身体のシルエット検出
  3. 画像処理の結果から3Dモデルを生成
    • 生成された3Dモデルから各部位の計測データが得られる

このアルゴリズムはZOZO New Zealandが開発したC++ライブラリによって提供されており、その中で、OpenCVやMediaPipeのような画像処理・機械学習のライブラリが使われています。MediaPipeはソースコードが公開されており、利用したい機能をZOZOFIT向けにカスタマイズできることから採用に至りました。

また、計測結果の3Dモデル描画は、WebGL(Three.js)で実装されたものをWeb Viewで表示する仕組みとなっており、iOSアプリではWKWebViewが使われています。

計測機能がこのような実装となっている大きな理由は、クロスプラットフォームのためです。ZOZOFITはAndroid・iOSの2つのプラットフォームでアプリを展開しており、主要機能である計測機能については両プラットフォームで共通のものを提供することが重要でした。そのためネイティブとは切り離された、両プラットフォームに対応する技術を用いて実装されています。

ZOZOFITに限らず、これまでのZOZOMATやZOZOGLASSといった計測プロダクトでもクロスプラットフォームは大きな関心事でした。これまでの計測プロダクトについては下記の記事がありますので、興味があればぜひご覧ください。

techblog.zozo.com techblog.zozo.com

さて、以下の図は、計測機能がどのように統合されているかを示したものです。

計測機能の統合

図4:計測機能の統合

iOSアプリのリポジトリ内で、サブモジュールとして計測ライブラリと3D Model Viewerのリポジトリを参照しています。計測ライブラリについては、CMakeコマンドによりXcodeプロジェクトを生成することで、ワークスペース内で利用できるようにしています。

iOSアプリの技術要素

計測プラットフォーム開発本部アプリ部の中岡です。ここではZOZOFIT iOSの技術要素について説明します。

使用技術

2023年3月時点では以下のような技術構成となっています。

  • 開発言語:Swift 5.7
  • 対応OS:iOS 15~
  • UIフレームワーク:SwiftUI(一部UIKit)
  • CI/CD:Bitrise
  • パッケージ管理:Swift Package Manager
  • ライブラリ:FactoryChartsSwiftGenSwiftLintswift-snapshot-testing など。
  • その他ツール:Figma、TestFlight、Firebase

対応OS

基本的に最新バージョンから1つ前のメジャーバージョンまでをサポートする方針となっています。開発当初はiOS 16がリリースされていなかったのですが、ZOZOFITがリリースされる2022年8月にはiOS 16がリリースされているということもあり開発当初からiOS 15~で開発していました。

また、開発体験に関してはiOS 14をサポートするより向上はしましたが、本アプリ開発においてそこまで大きく変わったという印象はありませんでした。

UIフレームワーク

基本的にSwiftUIをベースに開発していますが、一部実装が困難な部分はUIKitを使用しています。具体的には以下の図のように最前面にローディング画面を表示することがSwiftUIだけでは困難でした。そのためUIKitのUIWindowを使用して最前面に表示しています。

hierarchy

図5:ローディング表示時のView階層

CI/CD

CI/CDにはBitriseを使用しており、PRが作られた際に自動でテストを実行するワークフローとApp Store Connectにアップロードするワークフローがあります。また、これらの設定のbitrise.ymlは同リポジトリで管理しています。

パッケージ管理

パッケージの管理は全てSwift Package Managerで行なっています。また、SwiftLintやSwiftGenといったツールもプラグイン機能を活用しバージョン管理をしています。

その他ツール

デザイン、テスト用アプリの配布はそれぞれFigma、TestFlightを使用しています。また、FirebaseはCrashlytics、Analytics、Dynamic Linksを使用するために導入しています。Analyticsの導入については下記の記事を公開しているので興味がある方はこちらをご覧ください。

techblog.zozo.com

アーキテクチャ

基本的に以下のようなView、Config、Managerという構成をとっています。

  • View
    • いわゆる見た目の部分です。SwiftUI.Viewで書かれており、ユーザからのイベントをConfigに渡します。
  • Config
    • MVVMでいうViewModelのような役割です。ObservableObjectプロトコルに準拠したオブジェクトでViewの状態管理や受け取った値をManagerに渡します。
  • Manager
    • MVVMでいうModelのような役割です。アプリのビジネスロジック部分で計測アルゴリズムの実行や、計測データの管理などを行なっています。

プロジェクト構成

ZOZOFIT iOSのプロジェクト構成は以下の図のようになっています。コアロジックや共通コンポーネント、カスタムModifier等をパッケージ化しそれらをXcodeプロジェクトから呼び出しています。

プロジェクト構成

図6:ZOZOFIT iOSの依存関係

今後の課題

ローンチからまだ1年足らずということもあり、現状のZOZOFIT iOSにはいくつかの課題が残っています。

まずは、テストが行いづらいという点が挙げられます。現在一部のManagerが@Publishedプロパティを持っておりObservableObjectとしてViewから参照されています。Mock化するためにこれらのProtocolを定義したいのですが、SwiftのProtocolでは@Publishedプロパティを定義できずコンパイルエラーとなってしまいます。そのためこれらのManagerに依存しているViewやConfigのテストが行いづらくなってしまっています。加えて、ZOZOFITはプロダクトの特性上、カメラやセンサデータを使用するため計測機能をデバッグするには実機で動かす必要があり時間と手間がかかるといった課題もあります。これについては、カメラを使わず事前に用意した画像を読み込むようにすることで改善できます。ZOZO New Zealandの開発チームがSDKを作成する際にそのような機能を持つアプリを用意していたので、その機能をZOZOFITアプリにも取り込めると良いなと思っています。

また、計測機能の統合方法についても改善の余地があります。現在はCMakeによって、C++で書かれた計測ライブラリのXcodeプロジェクトを生成し、ワークスペース内で統合するというアプローチをとっています。しかし、理想的には計測ライブラリをXCFramework化して、統合することがよりシンプルで望ましいと考えています。

効率的に開発をするためにも今後チームで話し合いこれらの課題は解決していきたいです。

おわりに

ZOZOFITのiOSアプリについてその全体像をご紹介しました。アプリは昨年リリースされたばかりであり、より多くのユーザーに使っていただくために改善や新機能の追加を行なっています。例えば現在は機能開発に加えて、データをより活用できるようにGoogle Analyticsの測定箇所を見直したり分析レポートの作成に取り組んでいます。ZOZOFITはZOZO New Zealandとの協業のプロジェクトであり関係者が多く言語の壁もあるので簡単なプロジェクトではありませんが、プロジェクト全体の改善も行いながら進めているところです。

これからのグロースを目指し、海外チームと協業しながらSwiftUIを利用してiOSアプリ開発をしていく、ということに少しでも興味のある方は以下のリンクからぜひご応募ください。

corp.zozo.com

カテゴリー