TECH PLAY

Xcode

イベント

該当するコンテンツが見つかりませんでした

マガジン

該当するコンテンツが見つかりませんでした

技術ブログ

はじめに こんにちは。開発部でiOSエンジニアをしている野口です。 ヘルシカ - ダイエット・食事管理のための簡単カロリー計算 every, Inc. ヘルスケア/フィットネス 無料 ヘルシカのiOSアプリではXcode Cloudを使用して開発環境・本番環境への配布を行っています。本記事では、配布にかかっていた実行時間を約50%削減した方法を紹介します。 背景と課題 削減前のXcode Cloudの実行時間は約30分かかっていました。これを削減できれば、開発スピードの向上やQAから修正へのサイクルが回しやすくなり、品質の向上が期待できると考えました。 各ステップの実行時間はApp Store Connectのダッシュボードから確認できます。調査したところ、 ci_post_clone.sh の実行が全体の約62%を占めており、ここがボトルネックであることがわかりました。 ステップ 時間 割合 Run ci_post_clone.sh script 16分46.9秒 62.34% Run xcodebuild archive 6分17.9秒 23.39% Resolve package dependencies 2分2秒 7.55% その他(環境設定・取得・Export・後処理など) 1分48.5秒 6.72% Build Archive 合計 26分55.3秒 100.00% Prepare Build for App Store Connect 44.8秒 — 総合計 約27分40秒 — ※主要なステップ以外は「その他」にまとめています。 原因の分析 ci_post_clone.shとは ci_post_clone.sh は、Xcode Cloudがリポジトリをクローンした直後に自動で実行されるシェルスクリプトです。ビルドに必要な追加ツールのインストールや設定ファイルの書き換えなど、ビルド前の準備処理を記述します。以下の画像のPost-cloneと記述されている箇所で ci_post_clone.sh が動きます。 引用元: 実行していた処理 ci_post_clone.sh では、以下の処理を行っていました。 # ci_post_clone.sh #!/bin/sh brew install mint mint bootstrap -m ../Mintfile --overwrite y # Mintfile realm/SwiftLint@0.52.4 mono0926/LicensePlist@3.24.11 kiliankoe/swift-outdated@0.8.0 nicklockwood/SwiftFormat@0.53.3 Mintを使用して、以下のツールをインストールしていました。 SwiftLint : コードの静的解析 SwiftFormat : コードのフォーマット LicensePlist : ライセンスの管理 swift-outdated : 依存関係の更新確認 改善のアプローチ これらのツールはいずれも開発時に使用するものであり、Xcode Cloudでの配布時には実行する必要がありません。Xcode Cloudの役割はCDであり、配布作業のみ行えれば十分だからです。 そこで、「不要なツールのインストールをやめる」ことで実行時間を削減する方針としました。 キャッシュによる高速化を採用しなかった理由 「Mintのインストールをキャッシュすれば速くなるのでは?」と考えるかもしれませんが、Xcode Cloudのキャッシュ機能には制約があります。 GitHub ActionsやCircleCIなどのCI/CDツールでは、任意のパスやフォルダを指定してキャッシュできます。例えば ~/.mint をキャッシュしておけば、2回目以降のインストールを高速化できます。 一方、Xcode Cloudのキャッシュ対象は DerivedData配下のみ に限定されています。具体的にキャッシュされるのは以下の2つです。 Xcodeのビルドキャッシュ (インクリメンタルビルド用の中間成果物) Swift Package Managerで取得・ビルドされたライブラリ 任意のパスを指定する機能は提供されていないため、Homebrew経由でインストールしたMintなどはキャッシュの対象外です。つまり、 ci_post_clone.sh でのインストール処理は毎回フルで実行されることになります。 To reduce the amount of time it takes to perform a build, Xcode Cloud stores each build's derived data and other cached information for reuse in a secure and private way. — Xcode Cloud workflow reference | Apple Developer Documentation このキャッシュの制約があるからこそ、キャッシュで高速化するのではなく、そもそも不要な処理をXcode Cloudから取り除くアプローチが有効になります。 具体的には、 ci_post_clone.sh を削除してXcode CloudでのMintインストール自体をやめ、各ツールの実行はGitHub Actionsやローカル環境に移行しました。 各ツールの対応内容 SwiftLint・SwiftFormat ローカル環境でのビルド(Build Phase)とGitHub Actionsでのみ実行するようにしました。 GitHub Actionsの設定 # .github/workflows/ci.yml name : CI on : pull_request : branches : - develop jobs : swift_format : name : SwiftFormat runs-on : macos-latest steps : - uses : actions/checkout@v4 - name : Cache Mint packages uses : actions/cache@v4 with : path : ~/.mint key : ${{ runner.os }}-mint-${{ hashFiles('Mintfile') }} restore-keys : | ${{ runner.os }}-mint- - name : Install Mint run : brew install mint - name : Run SwiftFormat lint run : mint run swiftformat healthcare Packages --lint swift_lint : name : SwiftLint runs-on : macos-latest steps : - uses : actions/checkout@v4 - name : Cache Mint packages uses : actions/cache@v4 with : path : ~/.mint key : ${{ runner.os }}-mint-${{ hashFiles('Mintfile') }} restore-keys : | ${{ runner.os }}-mint- - name : Install Mint run : brew install mint - name : Run SwiftLint run : mint run swiftlint lint ローカル環境(Xcode Build Phase)の設定 XcodeのRun Script(Build Phase)でSwiftFormatとSwiftLintを実行します。Run ScriptはXcode Cloud上のビルドでも実行されるため、環境変数 CI が TRUE のときはスキップするようにしています(Xcode Cloudでは CI=TRUE が設定されます)。 if [ " $CI " = "TRUE" ]; then exit 0 fi if [ -d " /opt/homebrew/bin " ]; then export PATH =" $PATH :/opt/homebrew/bin " fi mint run swiftformat healthcare Packages mint run swiftlint lint LicensePlist もともとBuild PhasesのRun Scriptでビルドのたびにライセンス情報を自動生成していたため、生成物をGit管理していませんでした。今回の対応で生成物をGit管理に含め、Build PhasesからRun Scriptを削除しました。パッケージを変更した際にはローカルでライセンス情報を再生成する運用としています。 swift-outdated もともとXcode Cloudでは実行していなかったため、対応は不要でした。 結果 これらの対応により、Xcode Cloudの実行時間を約30分から約15分へ、約50%削減することができました。ビルドやパッケージ解決の設定を変えたわけではなく、 ci_post_clone.sh の処理を見直しただけでこれだけの効果が得られました。 まとめ Xcode Cloudの実行時間を削減するために、CDとして不要なツールのインストール処理を見直しました。Xcode CloudのキャッシュはDerivedData配下のみという制約があるため、キャッシュで高速化するのではなく、そもそも不要な処理をXcode Cloudから取り除くアプローチを採用しています。各ツールの実行はGitHub Actionsやローカル環境に移行し、CI/CDの役割を明確に分離しました。 Xcode Cloudの実行時間に課題を感じている方の参考になれば幸いです。
はじめに 株式会社エブリーでデリッシュキッチンのiOSアプリの開発をしている成田です。 iOS 26から、Appleの新しいデザイン言語である「Liquid Glass」が導入されました。 2026年4月の現時点では設定のフラグによって適用を回避できますが、次のXcodeのメジャーアップデートではこのフラグの廃止が見込まれています。 また、2027年春頃には新しいメジャーバージョンのXcodeでのビルドが必須になると考えられ、対応は避けられない状況です。 こうした背景から、すでにLiquid Glassへの対応を進めているiOSアプリ開発者の方も多いのではないでしょうか。 デリッシュキッチンでも現在ユーザーへのリリースを目指して対応を進めています。 本記事では、以下のような流れでデリッシュキッチンにおけるLiquid Glass対応への取り組みについて紹介したいと思います。Liquid Glassの概要については他の記事でも多く紹介されているので本記事ではできるだけ割愛します。 Liquid Glass対応の進め方 大まかな対応箇所 デリッシュキッチンにおける課題 AppleのLiquid Glassワークショップへの参加 Liquid Glass対応の進め方 キックオフと開発の流れ 今年の1月にPdMとデザイナー、エンジニアが集まりキックオフを行ってプロジェクトがスタートしました。 まず最初に、アプリのプロジェクト設定のオプトアウトフラグ UIDesignRequiresCompatibility を外した状態のアプリを社内に配布し、Liquid Glassがそのまま適用された状態で各画面をデザイナーに確認してもらいました。Appleの標準アプリや他のメジャーなアプリのUIも参考にしながら、対応が必要な箇所の洗い出しと優先度付け、そして大まかな工数見積もりを行いました。 また、対応方針については単にデザイン観点だけで決めるのではなく、技術的な実現可否や実装コストも踏まえながら、エンジニアとデザイナーで議論を重ねて整理していきました。デザインと実装の両面から検討することで、現実的かつ一貫性のある方針を定められていると感じます。 さらに、初期段階では一定期間を設けて集中的に実装を進めることで、実際の対応にどの程度の工数がかかるのかを把握することもでき、おおよそのベロシティ感を掴むことができました。 なお、参考事例としてAppleが紹介している デザイン事例集 も、実際にどのようにLiquid Glassがプロダクトに取り入れられているかを把握するうえで非常に参考になりました。 専任を置かず全員で対応する このプロジェクトでは、iOSチーム内に専任を置かず、各プロジェクトごとに分担して対応を進めています。 専任を設けると知見が特定のメンバーに偏り、今後の機能開発においてプロジェクトごとに実装のばらつきが生じる可能性があるためです。Liquid Glassのようなデザイン言語の変化は一部の対応にとどまらず、プロダクト全体に継続的に影響していくものだと考えています。 また、UIはデザイナーだけで完結するものではなく、エンジニアと連携しながら作り上げていくものです。こうした背景もあり、プロダクトに関わるiOSエンジニア全員で取り組む形で進めています。 独自フラグでコードを先行リリース 現在対応を進めているコードは、まだユーザー向けには公開せず、以下のような独自のフィーチャーフラグを設けることで、コード自体は順次リリースしつつ、ユーザーにはLiquid Glassが適用されない状態を保ったままにしています。 public enum LiquidGlassAvailability { /// Liquid Glass デザインが有効かどうかを返す。 /// iOS 26 以降かつ UIDesignRequiresCompatibility が設定されていない(または false)場合に true。 public static let isEnabled : Bool = { guard #available(iOS 26.0 , * ) else { return false } // UIDesignRequiresCompatibility が true の場合は互換モードなので Liquid Glass 無効 if let requiresCompatibility = Bundle.main.object(forInfoDictionaryKey : "UIDesignRequiresCompatibility" ) as? Bool , requiresCompatibility { return false } return true }() } このような進め方にしているのは、変更をため込むことでGitHub上のPRが滞留し、コンフリクトが発生しやすくなるのを防ぐためです。対応が完了した箇所から順次マージしていくことで、開発の流れをスムーズに保っています。 ユーザー向けの初回リリース時にはプロジェクト設定のオプトアウトフラグを取り除き、Liquid Glassが適用された状態で提供する予定です。また、リリース後も優先度に応じて段階的に適用範囲を広げていく方針です。 初回リリースに向けた大まかな対応箇所 ユーザーへの初回のリリースに向けて、優先度が高いのは以下の内容です。 ナビゲーションバー・タブバー周りの対応 最も優先度が高く、Liquid Glassの効果が大きい箇所がナビゲーションバーとタブバー周りです。Liquid Glassではこれらのバーが透過されることでコンテンツへの没入感が高まりますが、デリッシュキッチンでは元々これらのバーに対して背景色やボタンのスタイルなどを独自にカスタマイズしていました。Liquid Glassに対応するにあたり、これらの独自設定を取り除いていく作業が必要になりました。 レイアウトの修正 独自設定を削除していくと、画面によってコンテンツのレイアウトが崩れるケースが発生しました。Liquid Glassではナビゲーションバーやタブバーの背面にまでコンテンツが広がるレイアウトが前提となりますが、一部の画面ではそのような構造になっていなかったためです。各画面ごとにレイアウトを見直し、コンテンツがバーの裏側まで自然に潜り込むよう修正する作業も対応範囲に含まれています。 その他の表示崩れの修正 ここでは書ききれないので紹介を省きますが、上記の対応に加え、Liquid Glassの適用によって生じる細かな表示崩れについても最低限の修正を行ったうえでユーザーに向けた初回のリリースを行う予定です。 デリッシュキッチンにおける課題 ここでは、Liquid Glass対応を進める上でのデリッシュキッチンにおける課題をいくつかピックアップして紹介します。 ナビゲーションバー直下のカスタムViewの扱い デリッシュキッチンには、ナビゲーションバーの直下にタブやカスタムViewが配置されている画面がいくつかあります。単純にナビゲーションバーを透過にするだけでは、その下に続くカスタムViewとの境界が不自然になってしまい、コンテンツの表示領域も狭まってしまいます。これはLiquid Glassが目指すコンテンツへの没入感という思想に反してしまいます。 これらのカスタムViewをコンテンツ領域の中にどう自然に溶け込ませるか、デザインと実装の両面から検討する必要があり、現在取り組んでいる課題の一つです。 幅広い環境での検証体制 デリッシュキッチンはユーザー数も多く、現在は最新から3つのメジャーバージョンのiOSをサポートしています。Liquid GlassはiOS 26以降でのみ適用されますが、それ以前のOSでもレイアウト崩れが発生しないよう、すべてのサポートバージョンで表示を確認する必要があります。そのため、単一の環境での検証にとどまらず、複数バージョンをまたいだ確認が求められる点が大きな負担となっています。 また、弊社には専任のQAチームがないため、動作検証はPdM・デザイナー・エンジニアが協力して行っています。Liquid Glass対応のように影響範囲が広い変更では、確認すべき画面やパターンも多岐にわたるため、検証の抜け漏れを防ぎつつ、いかに効率的に進めていくかが課題となっています。 並行開発による手戻りリスク また、もう一つの課題として、通常の機能開発との並行進行があります。 現在のプロダクトでは複数のプロジェクトが並行して開発を進めており、Liquid Glass対応と並行して進行しています。そのため、新規機能の開発時にLiquid Glassの考慮が十分に行われないケースも発生しがちです。 その結果、後からデザインの調整や実装の修正が必要になり、手戻りが発生してしまう可能性があります。こうした手戻りをいかに防ぎ、現状の開発の中にLiquid Glass対応を組み込んでいくかも重要な課題となっています。 AppleのLiquid Glassワークショップへの参加 Liquid Glass対応の一環として、Appleが時折に開催しているワークショップに会社で参加する機会をいただき、3月にエンジニアとデザイナー数名で参加してきました。 ワークショップは、まずLiquid Glassの概要や設計思想、もたらす効果について一通り説明いただくところから始まり、その後はAppleのデザインのエバンジェリストの方と直接やり取りできる時間が設けられており、デリッシュキッチンにおける対応方針について質問やディスカッションを行いました。 自社アプリの課題を持ち込み、その場でフィードバックをもらえる形式だったため、抽象的なガイドラインだけではイメージしづらかった部分についても、具体的な方向性を確認することができました。 せっかくなので、ワークショップに参加して特に印象に残っている学びをいくつか紹介します。 ナビゲーションバーやタブバーで特色を出さない ナビゲーションバーやタブバーといった操作周りのUIで個性を出すのではなく、コンテンツでプロダクトの特色を表現することが重要であるという考え方が印象に残りました。 透過させることが目的ではない Liquid Glassは単に透過やブラーを適用すること自体が目的ではなく、コンテンツへのフォーカスを高めるための手段であるという話がありました。見た目だけをなぞるのではなく、どういう意図で使うかが重要だと感じました。 システムとの一貫性を保つ OS全体の表現と調和することが重要で、過度に独自のスタイルを持ち込むと違和感につながるという点も印象的でした。標準の振る舞いを尊重することが結果的に良い体験につながると感じました。 おわりに 本記事では、デリッシュキッチンにおけるLiquid Glass対応の取り組み状況についてご紹介しました。 同じようにLiquid Glassへの対応を進めている方にとって、少しでも参考になれば幸いです。 デリッシュキッチンのLiquid Glass対応のリリースもぜひ楽しみにしていてください!
こんにちは、LINEヤフー株式会社の福野です。社内のさまざまなアプリの開発を横断的に支援する仕事をしています。本記事では当社のAndroid・iOSアプリを衛星通信に対応させるための取り組みについてご...

動画

該当するコンテンツが見つかりませんでした

書籍