View in English

  • メニューを開く メニューを閉じる
  • Apple Developer
検索
検索を終了
  • Apple Developer
  • ニュース
  • 見つける
  • デザイン
  • 開発
  • 配信
  • サポート
  • アカウント
次の内容に検索結果を絞り込む

クイックリンク

5 クイックリンク

ビデオ

メニューを開く メニューを閉じる
  • コレクション
  • トピック
  • すべてのビデオ
  • 利用方法

その他のビデオ

  • 概要
  • トランスクリプト
  • コード
  • Networkフレームワークによる構造化された並行処理の実行

    Networkフレームワークは、Appleプラットフォーム上で低レベルのネットワーク接続を行う理想的な方法です。またiOS、iPadOSおよびmacOS 26では、構造化された並行処理のためのコーディングに最適です。接続、データやフレーム付きメッセージの送受信、受信接続のリッスン、ネットワークのサービス検索を行う方法について説明するとともに、それらに関する主なベストプラクティスについても紹介します。

    関連する章

    • 0:00 - ようこそ
    • 0:45 - 接続の作成
    • 7:22 - 送受信
    • 14:22 - 受信接続の受け入れ
    • 16:05 - ほかのデバイスの検出

    リソース

    • Building a custom peer-to-peer protocol
    • Network
    • NetworkBrowser
    • NetworkConnection
    • NetworkListener
      • HDビデオ
      • SDビデオ

    関連ビデオ

    WWDC25

    • Swiftの並行処理の活用
    • Wi-Fi Awareによるデバイスの接続性の強化

    WWDC18

    • Introducing Network.framework: A modern alternative to Sockets
  • このビデオを検索

    こんにちは Scottです ネットワーク処理コードを これまで以上に楽しく簡単に 記述できるようになる 改善点について皆さんに 紹介できるのがとても楽しみです ネットワークコードを 記述したことがない方は 本セッションを参考にしてください 記述したことがある方にも ワクワクする新しいAPIをご紹介します まず 接続を確立する方法を説明し 次に 接続を使用してデータを 送受信する方法を詳しく見ていきます

    その後 外部からの接続を リッスンする方法を紹介し 最後に ネットワーク上の 他のデバイスを検索し 接続する方法を説明します まず 接続の作成方法からです Networkフレームワークを使うと アプリ内で安全かつ構成可能な 最新の接続を作成できます ソケットやsockaddr 覚えにくいioctlを使う時代は 終わりました Networkフレームワークには Connect by Nameが備わっており 代わりに名前を解決してくれます 名前を解決すると Happy Eyeballsと呼ばれる アルゴリズムにより ユーザーを動的に接続するための 最適な解決済みアドレスが 効率的に選択されます

    TLSによるセキュリティが 直接ベイクされているため ユーザーのプライバシーを 保護するためだけに 通常は まったく異なる種類のAPIを使用して行う 別のライブラリの統合は必要ありません また ネットワークインターフェイスの 切り替えやプロキシも サポートしているため 作業者の介入なくWi-Fiアシストや マルチパスプロトコルなどを 利用できます

    QUICなどの最新の トランスポートプロトコルを サポートしているほか 独自のプロトコルと組み込みのプロトコルを 組み合わせることもできるため メッセージがA地点からB地点に 届かない理由を探るために デバッグを行う必要がなくなり ビジネスロジックやユーザー体験に 時間をかけることができます ネイティブアプリとWebアプリの両方を サポートする必要がある場合のために NetworkフレームワークにはWebSocketの 堅牢なサポートが備わっているため 1台のサーバで全クライアントアプリに 対応できます

    Networkフレームワークは 構成可能なようゼロから構築されています つまり Networkフレームワークを 選ぶことで なじみのある一連のAPIを 利用できるわけです ネットワークプロトコルが進化しても パフォーマンスとプライバシーを 向上させながら引き続き利用できます TCPとBSDソケットAPIを使って ネットワークコードを記述したことがあれば ご存知のように QUICなどに 切り替える際には 大幅な再記述が必要になります Networkフレームワークなら ワーキングランチ中に QUICに切り替えることが 可能になります iOSとmacOS 26では Networkフレームワークが Swiftの堅牢なサポートと 緊密に統合されており 非同期操作と 構造化並行処理が可能です ネットワーク処理コードがスムーズに 他のSwiftコードに適合されることで アプリを簡単にビルドし 保守できるようになります 初めてネットワーク処理に 取り組む方のために この例でなじみのない概念を 紹介しますが 最後には理解できているはずですので ご安心ください

    アプリを記述していて ポート1029でwww.example.comの サーバと通信するとします TLSを使用して 制約のないネットワーク上でのみ 接続したいと考えています エンドポイントは 接続する場所 プロトコルスタックは 接続方法を指し パラメータは接続する過程を 調整するのに役立ちます

    これらを組み合わせて NetworkConnectionを作成します 例を通して実際の仕組みを 見てみましょう

    目的のエンドポイントと プロトコルスタックを使って NetworkConnectionを初期化して 接続を作成します この例ではプロトコルスタックを TLSとして指定しています TCPとIPが示されているので カスタマイズしたい場合にのみ 値を指定しますが ほとんどの場合 デフォルト値で問題ありません

    デフォルト値を変更したい場合は 宣言により行います 例として この接続のIPの断片化を オフにします

    まず TLSの下でTCPプロトコルと IPプロトコルを指定する必要があります その後 オプションをカスタマイズして IPの断片化をオフに 設定できます

    ネットワーク使用量を 最小限に抑えるための 省データモードが有効になっている場合 制約付きネットワークインターフェイスの 使用を禁止するよう 接続の動作を変更します

    自動的に作成されたパラメータの デフォルト値は使用しないため コードを更新して 接続のパラメータを 変更します

    プロトコルスタックは変わりませんが この特定の接続において Networkフレームワークで 省データモードでない ネットワークインターフェイスだけが 使用されるよう設定する カスタムパラメータを追加しています いいですね SwiftUIの人気の秘訣である 宣言型のスタイルにより ユーザーインターフェイスコードと 似た感覚でネットワークコードが使えます

    ネットワークが常に利用できることが 理想ではありますが ネットワーク状況は常に変化します ソケットとは異なり NetworkConnectionは こうした状態の変化に対応できます

    接続が開始されると プロトコルのハンドシェイクを 実行しながら準備状態に 移行します 準備が完了すると 準備完了状態になります 接続がない場合 接続は 準備状態から 待機状態になります

    Networkフレームワークで ネットワーク状況の変化が検出されると リモートエンドポイントへの接続を 試行している間 準備状態に戻ります 接続状態が準備完了になると データを送受信できます

    接続が準備完了状態になると エラーが発生した場合 または接続が失われた場合に 状況を知らせるためのエラーを表示させ 失敗状態に移行します

    接続に関連付けられているタスクを 終了またはキャンセルすると 接続によってタスクが キャンセル状態に移行します 素晴らしいのは 必要としない限り 接続状態を意識する必要がない点です 送受信を呼び出すと こうした操作を 実行できる状態になるまで NetworkConnectionが待機します ユーザーインターフェイスを 更新するためなど 接続状態を確認する必要がある場合は 接続状態が変わると呼び出される ハンドラを インストールすることができます これで接続の作成方法が わかりました この接続を使ってネットワーク上で データを送受信してみましょう

    送信と受信はどちらも 非同期関数であり 接続がまだ開始されていない場合は どちらも接続を開始します

    送信はデータオブジェクトを取得し Networkフレームワークで データが処理されるまで タスクを一時停止します

    TLSとTCPは ストリームプロトコルなので データの受信時に必要なバイト数を 指定する必要があります この例では 読み取るバイト数を 正確に指定しています 受信はコンテンツとメタデータの タプルを返します この例では コンテンツのみを 返すよう指定しています

    これらの関数はどちらも 接続でエラーが 発生した場合にエラーをスローします 例えば 機内モードがオンのために ネットワークが失われた場合 関連するエラーを使って 転送が中断された理由を説明できます 受信するデータ量が わからない場合もあるでしょう この例では ネットワークから 画像を読み込んでいます 接続で受信する32ビット整数が 受信する必要のある 残りの画像データの バイト数を示しています その値を使用して画像の受信が 完了するまで繰り返し呼び出します

    最後の例では 正確なバイト数を指定する 受信バージョンを使用しています この例は 受信する最小バイト数と 最大バイト数を指定する 受信バージョンです この方法では ネットワークで 受信している画像のバイト数を コードで解析できるため 全体が完了するまで 待機する必要がなくなります TLSなどのバイトストリームプロトコルは 便利ですが 送受信するバイト数を フレーム化する必要がある場合も多いため バイト数ではなくメッセージに対処します 画像コンテンツの前にバイトストリームの 32ビット値を読み込むことで 画像の大きさを認識した例では 隣接する画像と区別するため 長さで画像がフレーム化されていました この方法を取る必要があるのは ストリーミングプロトコルでは メッセージの境界が保持されないためです つまり 個々の送信操作に 渡されるバイト数が 必ずしも接続の もう一方の端にある 受信操作から渡された バイト数であるとは限らないのです 例えば 3つのデータチャンクで 構成された送信を呼び出した場合 相手側は一度に1バイトずつ 一度にすべて あるいはそれ以外の形態で 受信する可能性があり これにより 堅牢なネットワーク処理アプリの記述が 大幅に複雑になる可能性がありますが

    Networkフレームワークならお役に立てます iOSとmacOS 26の新機能が 型 長さ 値 またはTLVの組み込みフレーマーです メッセージをフレーム化することで 接続の一方の端から送信したコンテンツを そのままもう一方の端で 受信できるフレーマーです

    TLVは メッセージに含まれる データを記述するのに使われる型と メッセージのデータサイズである 長さをエンコードする シンプルなメッセージプロトコルです それに続いて メッセージの 実際のコンテンツが送られます ネットワークプロトコルで 一般に使われるのが TLVで お使いのサーバで対応している 形式である可能性もあります 試してみましょう この例では GameMessage型を 送受信します GameMessageはメッセージ型として使う 列挙型です メッセージの内容はGameCharacterか GameMoveのいずれかです TLVの追加はプロトコルスタックへの 追加と同じくらい簡単です TLVによってメッセージが フレーム化されるため 送受信のインターフェイスは 若干異なります

    JSONEncoderを使って GameCharacter構造体を エンコードして送信してみます エンコードしたデータと一緒に メッセージの型を指定していることが わかります 次に TLVを使ってメッセージを 受信する方法を見てみましょう

    バイトストリームプロトコルを使った 前の例とは異なり TLVを使用する場合 受信するバイト数を 指定する必要はありません TLVがメッセージを 解析してくれるためです 受信したメッセージの型を 確認したいので コンテンツのタプルと メッセージに関連付けられている メタデータを受け取ります TLVの場合 メタデータには型が含まれます 型から受信したコンテンツの 種類を判断したら その情報を使ってデータをデコードし 受信したデータを印刷します これは特に 制御できない 既存のサーバやプロトコルと 相互運用する場合に効果的です それほど問題なく バイトをフレーム化して メッセージを 送受信できるようになりました バイトストリームプロトコルを 直接使用する場合と比べて大きな進歩です

    ではオブジェクトを直接送信できるとしたら どうでしょうか? iOSとmacOS 26の新機能で コード化可能な型の送受信に 対応できるようになり 一部の定型コードの扱いが 簡単になります

    文字を折りたたんだり 構造体をGameMessage列挙型自体に 移動したりできます コーダーはプロトコルスタックに 追加できるプロトコルで メッセージをフレーム化してくれるほか 自分でシリアル化や シリアル化解除することなく コード化可能な型を 送受信できます このコードではGameMessageを 送受信するため 送受信する型と コーダーでの データのフォーマット方法で コーダーを初期化します JSONとプロパティリスト形式の サポートが組み込まれているので この例ではJSONを選択します 自分でエンコードすることなく GameMessageを送信できます

    接続で受信を呼び出すと データオブジェクトと GameMessage間で 中間デコードを行うことなく GameMessageが直接返されます 追加の作業を行うことなく GameMessageを送受信できるため カスタムメイドのネットワークコードで 画面を散らからすことなく アプリのビジネスロジックや ユーザーインターフェイスに集中できます

    これで エンドポイントへの 接続を作成し その接続でデータを 送受信する方法がわかりました TCPやTLSなどの バイトストリームプロトコルについて プロトコルスタックに フレーミングプロトコルを追加して バイトストリームではなくメッセージに 対処する方法について学びました では 外部からの接続を リッスンするアプリはどうでしょうか

    外部からの接続は NetworkListenerで処理されます NetworkConnectionと同様に プロトコルスタックを宣言して初期化します 接続とは異なり リスナーには 送信メソッドも受信メソッドもありません

    これはリスナーが 新しい接続をリッスンし 呼び出し元に 届けるためです NetworkListenerには 渡されたハンドラに 新しい接続を届ける runメソッドがあります 仕組みを見てみましょう プロトコルスタックを指定して 宣言することで NetworkListenerを作成します この例では TLSで暗号化された GameMessageオブジェクトを 外部からの接続で送受信できます

    NetworkListenerでrunを呼び出すと runに渡したハンドラに 外部からの新しい接続が 届けられるようになります

    新しい接続ごとに NetworkListenerによって 新しいサブタスクが開始されます リスナーが外部からの 新しい接続を 継続的に届けるのを妨げる 心配をすることなく クロージャで非同期操作を 実行できます 新しい接続を受信すると NetworkConnectionの messagesプロパティを使って クライアントからの 受信メッセージを処理します これで既存のエンドポイントへの NetworkConnectionを作成し 新しい接続をリッスンする コードを作りました 今度は事前にわからない エンドポイントの NetworkConnectionを 作成したいと思います NetworkBrowserを使用すると 接続の作成時に使用できる エンドポイントを検出できます 今年のiOS 26の新機能はWi-Fi Awareで これは互換性のある 幅広いデバイスを 検出して接続できる クロスプラットフォームの ピアツーピアネットワークテクノロジーです DeviceDiscoveryUIフレームワークを 使用すれば Wi-Fi Awareを使っている近くの デバイスを見つけてペアリングできます Bonjourを使って広告されたサービスを 検索することもできます Wi-Fi Awareについて詳しくは 「Supercharge device connectivity with Wi-Fi Aware」をご覧ください Wi-Fi Awareを使う場合も Bonjourを使う場合も ネットワーク上の デバイスを見つけるには NetworkBrowserを使用します NetworkBrowserは検索対象を記述する ブラウズ記述子を受け取ります NetworkConnectionと同様に 検索方法を記述する パラメータも受け取ります ただし NetworkConnectionや NetworkListenerとは異なり NetworkBrowserは プロトコルスタックを受け取りません NetworkBrowserの唯一の役割が 接続に使用するエンドポイントを 返すことであるためです

    この例では NetworkBrowserを作成して Wi-Fi Awareサービスの Tic-Tac-Toeを使って 近くのデバイスを探します ブラウザでrunを呼び出すと 処理が開始され runに渡したハンドラに一連の エンドポイントが提供され始めます

    このアプリではエンドポイントに対する 希望はないため ブラウザから返される 最初のエンドポイントを選択します エンドポイントと一緒に.finishを返すと ブラウザの実行が停止され runからエンドポイントが 返されなくなります その後 このエンドポイントを使用して NetworkConnectionを初期化できます これは前の例で エンドポイントを使って NetworkConnectionを初期化したのと まったく同じ方法です このエンドポイントの 素晴らしい点は ブラウザが見つけてくれるため 事前に確認しておく必要が ないことです

    これらすべての新しいプロトコルのうち アプリで使用するプロトコルの 選び方について悩むかもしれません いい疑問です 答えは思っているほど 複雑ではありません 制御できないサーバや 他のデバイスと通信している場合 プロトコルは自動的に選択されます 例えば TCPでIPPを介して プリンタと通信する場合や 別のデバイス上の自分のアプリと 通信する場合は TLSまたはQUICを介して コーダーを使用すると間違いないでしょう

    HTTPネットワーク処理を行っていて 現在URLSessionを使用している場合は コードを変更する必要はありません NetworkフレームワークC APIを 使用している場合 またはSwiftで作業しており 完了ハンドラの使用を希望している場合も コードを変更する必要はありません URLSessionや任意の形式の Networkフレームワークを使用する場合も 優れた名前による接続のサポート コンポーザビリティ モビリティ 組み込みのセキュリティを利用できます

    簡単に振り返ってみましょう iOSとmacOS 26の新機能が NetworkConnection NetworkListener NetworkBrowserです TLVフレーム化を使う NetworkConnectionや コーダープロトコルで コード化可能な型を 受信する方法を学びました NetworkListenerは外部からの接続を リッスンするのに使用できます NetworkBrowserはネットワーク上の エンドポイントを検索するのに使用できます これらすべてにより ネットワークアプリの 記述がこれまで以上に簡単になります 以上です これらの新しいAPIは Swiftの構造化並行処理を念頭に置いて 構築されています SwiftUIでユーザーインターフェイスを 配置する場合のように宣言で作成されます タスクで実行され 実行対象のタスクが キャンセルされると 自動的にキャンセルされます これらの新しいAPIを試して Swiftの構造化並行処理を最大限に活用し コードをすっきりとさせ 大量の定型コードをなくしましょう アプリでNetworkフレームワークを 使用する場合と同じ パワーと柔軟性も得られます ありがとうございました

    • 4:04 - Make a connection with TLS

      // Make a connection
      
      import Network
      
      let connection = NetworkConnection(to: .hostPort(host: "www.example.com", port: 1029)) {
        TLS() 
      }
    • 4:41 - Make a connection with TLS and IP options

      // Make a connection
      
      import Network
      
      let connection = NetworkConnection(to: .hostPort(host: "www.example.com", port: 1029) {
        TLS {
          TCP {
            IP()
              .fragmentationEnabled(false)
          }
        }
      }
    • 5:07 - Make a connection with customized parameters

      // Make a connection
      
      import Network
      
      let connection = NetworkConnection(to: .hostPort(host: "www.example.com", port: 1029),
                                         using: .parameters {
        TLS {
          TCP {
            IP()
              .fragmentationEnabled(false)
          }
        }
      }
      .constrainedPathsProhibited(true))
    • 7:30 - Send and receive on a connection

      // Send and receive on a connection
      
      import Network
      
      public func sendAndReceiveWithTLS() async throws {
        let connection = NetworkConnection(to: .hostPort(host: "www.example.com", port: 1029)) {
          TLS()
        }
      
        let outgoingData = Data("Hello, world!".utf8)
        try await connection.send(outgoingData)
      
        let incomingData = try await connection.receive(exactly: 98).content
        print("Received data: \(incomingData)")
      }
    • 8:29 - Send and receive on a connection

      // Send and receive on a connection
      
      import Network
      
      public func sendAndReceiveWithTLS() async throws {
        let connection = NetworkConnection(to: .hostPort(host: "www.example.com", port: 1029)) {
          TLS()
        }
      
        let outgoingData = Data("Hello, world!".utf8)
        try await connection.send(outgoingData)
      
        let remaining32 = try await connection.receive(as: UInt32.self).content
        guard var remaining = Int(exactly: remaining32) else { /* ... throw an error ... */ }
        while remaining > 0 {
          let imageChunk = try await connection.receive(atLeast: 1, atMost: remaining).content
          remaining -= imageChunk.count
      
          // Parse the next portion of the image before continuing
        }
      }
    • 11:06 - Tic-Tac-Toe game messages

      // TicTacToe game messages
      
      import Network
      
      enum GameMessage: Int {
        case selectedCharacter = 0
        case move = 1
      }
      
      struct GameCharacter: Codable {
        let character: String
      }
      
      struct GameMove: Codable {
        let row: Int
        let column: Int
      }
    • 11:24 - Send TicTacToe game messages with TLV

      // Send TicTacToe game messages with TLV
      
      import Network
      
      public func sendWithTLV() async throws {
        let connection = NetworkConnection(to: .hostPort(host: "www.example.com", port: 1029)) {
          TLV {
            TLS()
          }
        }
      
        let characterData = try JSONEncoder().encode(GameCharacter(character: "🐨"))
        try await connection.send(characterData, type: GameMessage.selectedCharacter.rawValue)
      }
    • 11:53 - Receive TicTacToe game messages with TLV

      import Network
      
      public func receiveWithTLV() async throws {
        let connection = NetworkConnection(to: .hostPort(host: "www.example.com", port: 1029)) {
          TLV {
            TLS()
          }
        }
      
        let (incomingData, metadata) = try await connection.receive()
        switch GameMessage(rawValue: metadata.type) {
        case .selectedCharacter:
          let character = try JSONDecoder().decode(GameCharacter.self, from: incomingData)
          print("Character selected: \(character)")
        case .move:
          let move = try JSONDecoder().decode(GameMove.self, from: incomingData)
          print("Move: \(move)")
        case .none:
          print("Unknown message")
        }
      }
    • 12:50 - Tic-Tac-Toe game messages with Coder

      // TicTacToe game messages with Coder
      
      import Network
      
      enum GameMessage: Codable {
        case selectedCharacter(String)
        case move(row: Int, column: Int)
      }
    • 13:13 - Send TicTacToe game messages with Coder

      // Send TicTacToe game messages with Coder
      
      import Network
      
      public func sendWithCoder() async throws {
        let connection = NetworkConnection(to: .hostPort(host: "www.example.com", port: 1029)) {
          Coder(GameMessage.self, using: .json) {
            TLS()
          }
        }
      
        let selectedCharacter: GameMessage = .selectedCharacter("🐨")
        try await connection.send(selectedCharacter)
      }
    • 13:53 - Receive TicTacToe game messages with Coder

      // Receive TicTacToe game messages with Coder
      
      import Network
      
      public func receiveWithCoder() async throws {
        let connection = NetworkConnection(to: .hostPort(host: "www.example.com", port: 1029)) {
          Coder(GameMessage.self, using: .json) {
            TLS()
          }
        }
      
        let gameMessage = try await connection.receive().content
        switch gameMessage {
        case .selectedCharacter(let character):
          print("Character selected: \(character)")
        case .move(let row, let column):
          print("Move: (\(row), \(column))")
        }
      }
    • 15:16 - Listen for incoming connections with NetworkListener

      // Listen for incoming connections with NetworkListener
      
      import Network
      
      public func listenForIncomingConnections() async throws {
        try await NetworkListener {
          Coder(GameMessage.self, using: .json) {
            TLS()
          }
        }.run { connection in
          for try await (gameMessage, _) in connection.messages {
            // Handle the GameMessage
          }
        }
      }
    • 17:39 - Browse for nearby paired Wi-Fi Aware devices

      // Browse for nearby paired Wi-Fi Aware devices
      
      import Network
      import WiFiAware
      
      public func findNearbyDevice() async throws {
        let endpoint = try await NetworkBrowser(for: .wifiAware(.connecting(to: .allPairedDevices, from: .ticTacToeService))).run { endpoints in
          .finish(endpoints.first!)
        }
      
        // Make a connection to the endpoint
      }

Developer Footer

  • ビデオ
  • WWDC25
  • Networkフレームワークによる構造化された並行処理の実行
  • メニューを開く メニューを閉じる
    • iOS
    • iPadOS
    • macOS
    • tvOS
    • visionOS
    • watchOS
    Open Menu Close Menu
    • Swift
    • SwiftUI
    • Swift Playground
    • TestFlight
    • Xcode
    • Xcode Cloud
    • SF Symbols
    メニューを開く メニューを閉じる
    • アクセシビリティ
    • アクセサリ
    • App Extension
    • App Store
    • オーディオとビデオ(英語)
    • 拡張現実
    • デザイン
    • 配信
    • 教育
    • フォント(英語)
    • ゲーム
    • ヘルスケアとフィットネス
    • アプリ内課金
    • ローカリゼーション
    • マップと位置情報
    • 機械学習とAI
    • オープンソース(英語)
    • セキュリティ
    • SafariとWeb(英語)
    メニューを開く メニューを閉じる
    • 英語ドキュメント(完全版)
    • 日本語ドキュメント(一部トピック)
    • チュートリアル
    • ダウンロード(英語)
    • フォーラム(英語)
    • ビデオ
    Open Menu Close Menu
    • サポートドキュメント
    • お問い合わせ
    • バグ報告
    • システム状況(英語)
    メニューを開く メニューを閉じる
    • Apple Developer
    • App Store Connect
    • Certificates, IDs, & Profiles(英語)
    • フィードバックアシスタント
    メニューを開く メニューを閉じる
    • Apple Developer Program
    • Apple Developer Enterprise Program
    • App Store Small Business Program
    • MFi Program(英語)
    • News Partner Program(英語)
    • Video Partner Program(英語)
    • セキュリティ報奨金プログラム(英語)
    • Security Research Device Program(英語)
    Open Menu Close Menu
    • Appleに相談
    • Apple Developer Center
    • App Store Awards(英語)
    • Apple Design Awards
    • Apple Developer Academy(英語)
    • WWDC
    Apple Developerアプリを入手する
    Copyright © 2025 Apple Inc. All rights reserved.
    利用規約 プライバシーポリシー 契約とガイドライン