Apple、iOS 27のApp Store提出受付を開始:必須となるシーンライフサイクルに向けたユニバーサルリンク対応

opoinstall
2026-09-14
5 min read

AppleがiOS 27のアプリ提出受付を開始しました。2026年9月9日、AppleはiOS 27、iPadOS 27、macOS 27、tvOS 27、visionOS 27、watchOS 27に向けたApp Storeへの提出受付を正式に開始し、9月14日の一般公開に先駆けてXcode 27のリリース候補版(RC)を公開しました。今回の提出受付開始により、エンジニアチームは初日からアップデートを適用可能ですが、Appleは2つの重要なプラットフォーム境界を設けました。iOS 27 SDKを用いたビルドでは「UIKitシーンベースのライフサイクル」への移行が必須となり、2027年4月からはすべてのApp Store提出においてiOS 27およびiPadOS 27 SDK以降の使用が義務付けられます。iOSソフトウェアアーキテクトやモバイルインフラ担当者、グロースエンジニアにとって、iOS 27におけるユニバーサルリンクのルーティングを習得することは、従来の単一ウィンドウという前提を廃し、リンクハンドラを現代的な UIWindowSceneDelegate ライフサイクルへ移行させ、動的な表示環境全体でルーティング状態が適切に管理されるようにするために不可欠です。

App Store提出ウィンドウ、実行環境要件、および2027年の義務化

iOS 27のアプリ提出受付開始は、Appleのプラットフォーム移行サイクルの始まりを意味します。Apple Developer Portalで発表された通り、開発者はXcode 27 RCを使用してソフトウェアのコンパイルと検証を行い、TestFlightを通じてビルドをテストし、Appleの6つのプラットフォームすべてでアプリ審査に提出できるようになりました。

要点まとめ

  • 提出期間開始: 2026年9月14日(月)の一般公開に先立ち、2026年9月9日よりiOS 27 SDKでビルドされたアプリを提出可能です。
  • iOS 27 SDKでのシーンライフサイクル必須化: iOS 27 SDKを使用してビルドされたUIKitアプリは、シーンベースのライフサイクルを採用しない場合、ランタイムで起動に失敗します。
  • 2027年4月の最低要件: 2027年4月以降、App Store Connectへアップロードされるすべてのアプリおよびアップデートは、iOS 27およびiPadOS 27 SDK以降でビルドされている必要があります。

Apple Developer App Store提出開始の告知バナー

9to5Macの報道にある通り、現時点でのiOS 27 SDKへの移行は任意ですが、Xcode 27と最新SDKを使用することで、Apple Intelligence連携や基盤モデルフレームワークを早期に活用できます。また、App Store Connectでは、プロダクトページのヘッダー更新や、ペアレンタルコントロール機能である「利用時間(Time Allowances)」に関する年齢制限コンプライアンスの質問票など、マーチャンダイジング関連のアップデートも導入されています。

UIの変更やマーチャンダイジング機能を超えて、最新SDKでのビルドはコアアーキテクチャの刷新を強制します。UIKitシーンベースのライフサイクルへの移行に関する公式ドキュメントでは、iOS 27以降、最新SDKでビルドされたアプリはシーンベースのライフサイクルを採用しなければ起動しないことが明記されており、長年続いてきた従来のApp Delegateによるウィンドウ管理の廃止が完了します。

+-------------------------------------------------------------------------+
|                  Apple SDK提出およびランタイムタイムライン                |
+-------------------+--------------------+--------------------------------+
| マイルストーン    | 管理レイヤー       | 運用の技術スコープ             |
+-------------------+--------------------+--------------------------------+
| 2026年9月9日      | App Store Connect  | Xcode 27 RC & iOS 27 SDKビルド |
|                   |                    | 提出受付開始 (任意)            |
| 2026年9月14日     | OS公開             | iOS 27 対応デバイス向け一般公開|
| iOS 27 最新SDK    | ランタイム契約     | UIKitアプリはシーンライフ      |
|                   |                    | サイクル採用必須(非採用で起動不可)|
| 2027年4月         | App Store義務化    | 全アプリアップロード時に       |
|                   |                    | iOS/iPadOS 27 SDK必須          |
+-------------------+--------------------+--------------------------------+

2027年4月まで猶予期間はありますが、Xcode 27でコンパイルを行う技術チームは、単一のグローバルな UIWindow を前提としたルーティングパターンを即座に修正する必要があります。

シーンライフサイクルの分解とマルチウィンドウへの配慮

長年、iOSアプリは UIApplicationDelegate を入り口としてディープリンクを処理し、application(_:open:options:)application(_:continue:restorationHandler:) に依存してきました。この単一ウィンドウモデルにおいて、エンジニアチームはグローバルなシングルトンを中心にナビゲーションルーターを構築し、UIApplication.shared.windows.first(where: { $0.isKeyWindow }) を参照してターゲットとなるビューコントローラーを表示するのが一般的でした。

Appleプラットフォーム開発者向けアイコンとSDKツールセット

重要なのは、「シーンライフサイクルの採用」と「マルチウィンドウへの対応」を区別することです。iOS 27 SDKでビルドされたUIKitアプリでは UIScene ライフサイクルの採用が必須ですが、同時に複数のウィンドウをサポートするかどうかは個別の構成設定です。しかし、iPadOSのSplit ViewやVision Proの空間ウィンドウ、iPhone Duoのようなマルチディスプレイ環境など、現代のハードウェアおよびソフトウェア環境は、アプリケーションをマルチウィンドウ環境に置くケースを増やしています。

アプリが複数のウィンドウをサポートしたり、動的なSplit Viewで共存したりする場合、従来のシングルトンによるルーティングは重大な表示障害を引き起こします:

  1. ウィンドウコンテキストの曖昧さ: アプリが複数のウィンドウインスタンスをサポートしている場合、グローバルなシングルトン経由でルーティングされるユニバーサルリンクでは、どのシーンがナビゲーション状態を受け取り、表示すべきかを特定できません。
  2. バックグラウンドシーンのハイジャック: UIApplication.shared が返す最初のキーウィンドウに遷移先のビューコントローラーを表示しようとすると、非アクティブまたはバックグラウンドにあるシーンに新しい画面がプッシュされ、ユーザーが現在アクティブな画面に変化がないと感じる事態が発生します。
  3. 階層表示の競合: 任意のウィンドウコンテキストでルーティングコマンドを実行すると、表示状態の不整合、ナビゲーション順序の重複、あるいは非アクティブなビュー階層からの表示試行といった問題が生じる可能性があります。
+-------------------------------------------------------------------------+
|               従来のシングルトンルーティング vs. マルチシーンルーティング |
+-------------------------------------------------------------------------+
|                                                                         |
|  [ 従来の欠陥モデル: グローバルアプリケーションウィンドウの前提 ]      |
|                                                                         |
|  ユニバーサルリンク受信                                                 |
|         |                                                               |
|         v                                                               |
|  [ App Delegate / グローバルルーターシングルトン ]                      |
|         |                                                               |
|         |-- クエリ: グローバルキーウィンドウ検索 (windows.first)        |
|         v                                                               |
|  [ 任意のウィンドウで表示 (リスク: バックグラウンドへの表示など) ]      |
|                                                                         |
+-------------------------------------------------------------------------+
|                                                                         |
|  [ モダンシーンベースモデル: コンテキストに基づいたUIWindowScene配信 ]  |
|                                                                         |
|  ユニバーサルリンク受信                                                 |
|         |                                                               |
|         +---------------------------------------+                       |
|         | (起動時のシーン接続)                  | (既存シーンでの受信)  |
|         v                                       v                       |
|  [ scene(_:willConnectTo:options:) ]    [ scene(_:continue:) ]          |
|         |                                       |                       |
|         +-------------------+-------------------+                       |
|                             |                                           |
|                             v                                           |
|  [ シーンコンテキスト内でのNSUserActivity抽出 ]                         |
|         |                                                               |
|         v                                                               |
|  [ 該当シーンのローカル階層でのターゲット表示 ]                         |
|                                                                         |
+-------------------------------------------------------------------------+

これらの問題を回避するため、iOS 27 SDKを使用してビルドを行う開発者は、Apple Universal Linksを、UIWindowSceneを用いたアプリライフサイクルの管理で文書化されたシーンライフサイクルを通じて厳密に処理する必要があります。

UIKitはシーンの実行状態に応じてリンクの配信を分岐させます:

  • 起動時やアクティブ化時のシーン接続: アプリの起動やアクティブ化の過程でシーンが接続され、接続オプションにユニバーサルリンクのアクティビティが含まれている場合、UIKitは connectionOptions ペイロード内の scene(_:willConnectTo:options:) を通じて NSUserActivity を配信します。
  • 実行中または一時停止中のシーン: シーンが既に接続されており、メモリ内で実行中または一時停止中の場合、UIKitはアクティビティを直接 scene(_:continue:) へ配信します。

いずれの実行フローにおいても、ナビゲーションはUIKitが渡す特定の UIWindowScene インスタンスに対して相対的に実行し、ターゲットとなるビューコントローラーがそのシーン自体のウィンドウ階層上でインスタンス化されるようにする必要があります。

// iOS 27 UIKitシーンベースのライフサイクル準拠とマルチウィンドウ実行をサポートするための
// シーンセーフなユニバーサルリンクルーティングのSwift実装例

import UIKit

struct DeepLinkRoute {
    enum Destination {
        case productDetail(sku: String)
        case campaignLanding(campaignId: String)
        case generalWebFallback(url: URL)
    }
    
    let destination: Destination
    let rawURL: URL
    
    static func parse(from url: URL) -> DeepLinkRoute {
        guard let components = URLComponents(url: url, resolvingAgainstBaseURL: true) else {
            return DeepLinkRoute(destination: .generalWebFallback(url: url), rawURL: url)
        }
        
        let pathSegments = components.path.split(separator: "/").map(String.init)
        if let productIndex = pathSegments.firstIndex(of: "products"), productIndex + 1 < pathSegments.count {
            let sku = pathSegments[productIndex + 1]
            return DeepLinkRoute(destination: .productDetail(sku: sku), rawURL: url)
        }
        
        if let campaignId = components.queryItems?.first(where: { $0.name == "campaign_id" })?.value {
            return DeepLinkRoute(destination: .campaignLanding(campaignId: campaignId), rawURL: url)
        }
        
        return DeepLinkRoute(destination: .generalWebFallback(url: url), rawURL: url)
    }
}

class SceneDelegate: UIResponder, UIWindowSceneDelegate {
    var window: UIWindow?

    // シナリオ1: アプリ起動時やアクティブ化時にユニバーサルリンクを受け取ってシーン接続する場合
    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        guard let windowScene = scene as? UIWindowScene else { return }
        
        // このウィンドウシーンコンテキストに厳密に紐付いたウィンドウを初期化
        let window = UIWindow(windowScene: windowScene)
        let navigationController = UINavigationController(rootViewController: MainDashboardViewController())
        window.rootViewController = navigationController
        self.window = window
        window.makeKeyAndVisible()
        
        // このシーン接続がユニバーサルリンクアクティビティによって開始されたか確認
        if let userActivity = connectionOptions.userActivities.first(where: { $0.activityType == NSUserActivityTypeBrowsingWeb }),
           let incomingURL = userActivity.webpageURL {
            let route = DeepLinkRoute.parse(from: incomingURL)
            routeWithinSceneContext(route: route, on: navigationController)
        }
    }

    // シナリオ2: 既に実行中またはメモリ内で一時停止中のシーンにユニバーサルリンクを配信する場合
    func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {
        guard userActivity.activityType == NSUserActivityTypeBrowsingWeb,
              let incomingURL = userActivity.webpageURL,
              let navigationController = self.window?.rootViewController as? UINavigationController else {
            return
        }
        
        let route = DeepLinkRoute.parse(from: incomingURL)
        routeWithinSceneContext(route: route, on: navigationController)
    }

    /// このシーンのビューコントローラー階層内でのみナビゲーションを実行する
    /// UIApplication.shared.windowsへのクエリを回避し、バックグラウンドシーンの破損を防ぐ
    private func routeWithinSceneContext(route: DeepLinkRoute, on navigationController: UINavigationController) {
        switch route.destination {
        case .productDetail(let sku):
            let detailVC = ProductDetailViewController(sku: sku)
            navigationController.pushViewController(detailVC, animated: true)
            
        case .campaignLanding(let campaignId):
            let campaignVC = CampaignViewController(campaignId: campaignId)
            navigationController.present(campaignVC, animated: true, completion: nil)
            
        case .generalWebFallback(let url):
            // 未対応のURLや外部URLはシステムのURLハンドラ経由で開く
            UIApplication.shared.open(url, options: [:], completionHandler: nil)
        }
    }
}
// ビューコントローラーの定義を省略...

下流のモバイル獲得とインストール境界

シーンベースのルーティングは、アプリインストール後のインアプリナビゲーションに適切なライフサイクルコンテキストを提供しますが、マーケティングや顧客獲得キャンペーンは、より広範で分離されたライフサイクルで動作します。獲得ファネルの上流では、外部のモバイルウェブページ、パートナーマーケティングキャンペーン、デジタル媒体を通じて見込みユーザーが接触します。

ユーザーがマーチャントやサービスに関連付けられたユニバーサルリンクをクリックした際のOSの動作は、端末へのインストール状況によって分かれます:

+-------------------------------------------------------------------------+
|             分離された下流のモバイル獲得ジャーニー                      |
+-------------------------------------------------------------------------+
|                                                                         |
|  [ 外部接点: H5キャンペーンランディング / プロモーションリンク ]        |
|         |                                                               |
|         |-- (ユーザーがiOSデバイスでリンクをタップ)                      |
|         v                                                               |
|  [ iOSがAASA(Apple-App-Site-Association)を検証 ]                     |
|         |                                                               |
|         +---------------------------------------+                       |
|         |                                       |                       |
|         v                                       v                       |
|  [ アプリがインストール済み ]         [ アプリが未インストール ]        |
|         |                                       |                       |
|         v                                       v                       |
|  [ UIWindowSceneDelegate 経由で       [ ブラウザでWeb先に遷移 ]         |
|    直接シーンへハンドオフ ]                                             |
|         |                                       |                       |
|         v                                       v                       |
|  [ ネイティブアプリ内へ移動 ]         [ ストアDLのCTAをタップ ]         |
|                                                 |                       |
|                                                 v                       |
|                                       [ App Storeへルーティング ]       |
|                                                 |                       |
|                                                 v                       |
|                                       [ 通常のストアフローではWebの     |
|                                         コンテキストを自動復元不可 ]    |
|                                                 |                       |
|                                                 v                       |
|                                       [ 遅延ディープリンクエンジン ]    |
|                                                 |                       |
|                                                 v                       |
|                                       [ 初回起動時にコンテキスト復元 ]  |
|                                                                         |
+-------------------------------------------------------------------------+

アプリが既にユーザー端末にインストールされている場合、対象となるユニバーサルリンクはWeb先ではなく、インストール済みのアプリを直接開きます。しかし、対象アプリが未インストールの場合、リンクはユーザーのブラウザでWeb先のランディングページを開きます。

その後、アプリをインストールしたユーザーが初回起動した際、標準的なApp Storeのインストールフローでは、元々のWeb URLやキャンペーンコンテキストを自動的に復元することはできません。そのため、アプリの初回起動時には一般的なウェルカム画面が表示され、本来のコンバージョンフローから脱落してしまう可能性があります。

このインストール境界のギャップを解消するため、エンジニアチームは以下のようなリンク処理フレームワークを検討します:

ルーティングアーキテクチャ インストール済みアプリの処理 未インストール時のフォールバック コンテキスト保存 運用の所有モデル
カスタムURIスキーム ネイティブコードのスキーム登録によりインターセプト アプリ不在時に宛先なし(別途Web/ストア対応が必要) なし(ストア経由で消失) 自社所有(運用負荷高)
認証済みユニバーサルリンク シーンライフサイクル経由で直接階層へルーティング Webランディングページへ遷移 なし(ストア経由でパラメータ消失) ドメイン+アプリ所有 (AASAとDNS設定が必要)
遅延ディープリンクアーキテクチャ ユニバーサルリンクやネイティブスキームに委譲 Web経由でストアインストールへ誘導 初回起動時にインストール前のパラメータを復元 SDK支援型 (属性管理用クライアント/サーバーフレームワーク)

エンタープライズ製品アーキテクチャにおいて、モバイルエンジニアチームはBranch、AppsFlyer、Adjust、または Opoinstall といった専用の遅延属性計測インフラを導入しています。Opoinstallのようなプラットフォームは、App Storeへのリダイレクト前に、チャネルIDや紹介トークン、ディープコンテンツルートなどのインストール前キャンペーンメタデータをWeb層で記録します。アプリの初回起動時、クライアントSDKは属性計測のバックエンドに対してセッション照合を行い、キャッシュされたパラメータを取得します。Opoinstallのホームページにある公式ドキュメントによると、この遅延パラメータ受け渡しフレームワークにより、最大98%の対象インスタンスで初回起動時にパラメータを復元でき、手動プロモーションコードに代わる自動化された手段を提供します。

シーンベースのインアプリナビゲーションと、インストール境界を越える獲得メカニズムを切り離すことで、開発組織は新しいOSアップデートや多様なウィンドウ環境に対応できるレジリエントな顧客ジャーニーを構築できます。

よくある質問 (FAQ)

iOS 27 SDKを即座に導入する必要がありますか?
いいえ。Xcode 27 RCとともに提出期間は2026年9月9日に開始されましたが、iOS 27 SDKの採用は短期的には任意です。開発者は2027年4月まで、以前のサポートされているSDKでビルドしたアップデートを継続して提出できます。2027年4月以降、App Store Connectに提出されるすべての新規アプリおよびアップデートは、iOS 27およびiPadOS 27 SDK以降を使用してビルドする必要があります。
iOS 27のシーンライフサイクル要件では、複数のウィンドウのサポートが義務付けられていますか?
いいえ。iOS 27 SDKでビルドされたUIKitアプリでは `UIScene` ライフサイクルの採用が必須ですが、複数のウィンドウを同時にサポートするかどうかは任意です。アプリはシーンライフサイクルを採用しつつ、ウィンドウインスタンスを1つに制限することも可能です。しかし、`UIWindowSceneDelegate` を採用することで、アプリのルーティングアーキテクチャがSplit Viewや外部ディスプレイ、折りたたみ式デバイスなどの将来の環境に対応できるようになります。
アプリの起動時と実行中の両方で、ユニバーサルリンクをキャプチャするにはどうすればよいですか?
シーンを採用したモダンなUIKitアーキテクチャでは、`UIWindowSceneDelegate` 内で以下の2つのデリゲートメソッドを実装します: 1. `scene(_:willConnectTo:options:)`: 起動時またはアクティブ化時にシーンが接続される際、`connectionOptions.userActivities` を検査してリンクURLを抽出します。 2. `scene(_:continue:)`: ターゲットシーンが既に接続されメモリ内で実行中の場合、`NSUserActivity` を受信します。

参考文献

Share this article