> For the complete documentation index, see [llms.txt](https://docs.payments.thalescloud.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.payments.thalescloud.io/push-provisioning/ja/implement-push-provisioning/implement-push-to-digital-wallets/apple-wallet-extension.md).

# Apple Wallet拡張機能

## Apple Wallet 拡張機能

Apple Wallet 拡張機能を使用すると、イシュアアプリケーションに加えて、エンドユーザーが Apple Wallet アプリケーションから直接カードを検出してプロビジョニングできるようになります。

アプリケーション拡張を介して、イシュアアプリケーションの外部でカスタム機能やコンテンツを公開し、エンドユーザーが Apple Wallet やシステムとやり取りしている間にそれらを利用できるようにできます。

Apple Wallet アプリケーション内でのカードのプロビジョニングは、支払いカードの詳細を手動で入力する必要を回避することで、アプリ内の体験を向上させます。

次を参照してください [Apple 拡張機能の概要](https://developer.apple.com/library/archive/documentation/General/Conceptual/ExtensibilityPG/ExtensionOverview.html) iOS 拡張機能に関する一般情報については。

### ユーザーエクスペリエンス

エンドツーエンドの Apple Wallet 拡張フローには主に 2 つのフェーズがあります:

1. Apple Wallet はイシュアアプリケーションにプロビジョニング可能なカードがあることを検出します。
2. エンドユーザーが認証して追加するカードを選択すると、Apple Wallet は D1 SDK を介してイシュアアプリケーションからプロビジョニングペイロードを要求します。

#### 検出と認証

<figure><img src="/files/de1d4b764ff4d558eab24813b79ab342aa4e13bd" alt="Apple Wallet showing issuer application option for adding a card"><figcaption><p>カードがプロビジョニング可能な場合、Apple Wallet はイシュアアプリケーションをオプションとして表示します。</p></figcaption></figure>

{% stepper %}
{% step %}

#### Apple Wallet でイシュアアプリケーションを検出する

Apple Wallet はイシュアアプリケーションにカードが利用可能かどうかを確認します。カードが利用可能な場合、イシュアアプリケーションがオプションの一覧に表示されます。
{% endstep %}

{% step %}

#### エンドユーザーがイシュアアプリケーションを選択する

エンドユーザーがイシュアアプリケーションを選択すると、Apple Wallet はイシュアアプリケーションの UI 拡張をトリガーしてエンドユーザーを認証します。
{% endstep %}

{% step %}

#### エンドユーザーを認証する

イシュアアプリケーションの UI 拡張は、メインのイシュアアプリケーションと同じ認証情報と方法（例えば、手動ログインや生体認証）を使用してエンドユーザーを認証します。
{% endstep %}
{% endstepper %}

#### カードの選択とプロビジョニング

<figure><img src="/files/f50eca3c1fd6a4253249802e1bb0e45480e3f3b5" alt="Apple Wallet showing available cards from the issuer application"><figcaption><p>Apple Wallet はイシュアアプリケーションから利用可能なカードを取得して表示します。</p></figcaption></figure>

{% stepper %}
{% step %}

#### Apple Wallet が利用可能なカードを取得する

Apple Wallet は非 UI 拡張を通じてイシュアアプリケーションに利用可能なカードの一覧を要求します。エンドユーザーは追加するカードの一覧を確認できます。
{% endstep %}

{% step %}

#### カード詳細を表示する

エンドユーザーはカードを追加する前にカードの詳細（例えば、カードデザイン、商品タイトル、下4桁）を確認できます。
{% endstep %}

{% step %}

#### 利用規約に同意する

エンドユーザーはイシュアおよび決済ネットワークの利用規約を確認して同意します。
{% endstep %}

{% step %}

#### プロビジョニングペイロードとトークン化

選択された各カードについて、Apple Wallet はイシュアアプリケーションからプロビジョニングペイロードを要求し、その後決済ネットワーク TSP とともにトークン化フローを開始します。
{% endstep %}
{% endstepper %}

### 拡張機能

Apple Wallet 統合には、イシュアアプリケーションから 2 種類の拡張機能が必要です:

* **非 UI 拡張**\
  拡張フローとカードの可用性のステータスを報告します。これはカードの検出およびプロビジョニングペイロードのステップをカバーします。D1 SDK のベースクラスを拡張して実装されます `D1IssuerProvisioningExtensionHandler`.
* **UI 拡張**\
  エンドユーザーを認証します。これはイシュアアプリケーションと同じログイン認証情報を使用する別の画面です。次を実装します `D1IssuerProvisioningExtensionAuthorizationProviding` プロトコル。

{% hint style="info" %}
Apple Wallet 拡張機能はイシュアアプリケーションと同時にインストールされます。Apple Wallet が追加可能なパスを検出して拡張機能を表示するには、エンドユーザーが少なくとも一度イシュアアプリケーションを起動する必要があります。
{% endhint %}

D1 SDK は非 UI 拡張のためのベース実装を提供するため、完全なロジックを自身で実装する必要はありません。イシュアアプリケーションは次を呼び出します `D1Task.configure()` とともに `WalletExtensionConfig` アプリケーション起動時に拡張機能とカード詳細を共有するために。インストール後にこの構成は一度だけ必要ですが、カード情報を最新に保つために毎回のアプリ起動時に呼び出すことを推奨します。

<figure><img src="/files/72bf0874aba9947cece7f78f26828526731114cc" alt="High-level flow for configuring the Apple Wallet extension via D1 SDK"><figcaption><p>ハイレベルフロー: イシュアアプリケーションが D1 SDK を構成して Apple Wallet がカードを検出できるようにします。</p></figcaption></figure>

UI 拡張での認証が成功した後、イシュアアプリケーションは次を呼び出す必要があります `D1IssuerProvisioningExtensionAuthorizationProviding.login()` SDK が非 UI 拡張のステップを続行できるようにするためです。

### シーケンス図

#### 1. Apple Wallet がイシュアアプリケーションのボタンを表示する

<figure><img src="/files/295df1beafaa4048274e4a378707b2add779f2ec" alt="Sequence diagram showing how Apple Wallet discovers the issuer application"><figcaption><p>Apple Wallet はイシュアアプリケーションにプロビジョニング可能なカードがあることを検出します。</p></figcaption></figure>

#### 2. エンドユーザーの認証

<figure><img src="/files/2cab8629271f1b0b94d2eb4c983612018a014276" alt="Sequence diagram showing Apple Wallet triggering issuer UI extension for authentication"><figcaption><p>Apple Wallet は認証のためにイシュアアプリケーションの UI 拡張を起動します。</p></figcaption></figure>

#### 3. 利用可能なカードが表示される

<figure><img src="/files/8822cc446817b0ec29aee5115ff156d4c588adb5" alt="Sequence diagram showing Apple Wallet requesting card list from issuer"><figcaption><p>Apple Wallet は利用可能なカードの一覧を要求してエンドユーザーに表示します。</p></figcaption></figure>

#### 4. トークン化

<figure><img src="/files/72671ee1f69237c0852614028c3bbf3a41c25319" alt="Sequence diagram showing Apple Wallet requesting provisioning payload and tokenizing"><figcaption><p>Apple Wallet はプロビジョニングペイロードを要求し、選択されたカードをトークン化します。</p></figcaption></figure>

### D1 SDK を介して Apple Wallet を統合する

#### SDK 構成

次を実行するとき [iOS SDK の初期化](/push-provisioning/ja/integrate-the-d1-sdk/getting-started/configuration/3.-initialization/ios-initialization.md)イシュアアプリケーションは次も呼び出す必要があります `configure(ConfigParams.walletExtensionConfig(...))` および次を提供します:

**`cardParamsList`**

単一の `consumerId` および単一の `issuerId`:

* `cardParamsList` を持つ場合にこのバリアントを使用します – カード ID、カードデザイン、商品タイトル、および下4桁の一覧。カードデザインと商品タイトルは Apple Wallet に表示されます。
* `appGroupID` – D1 SDK がイシュアアプリケーションとその拡張機能の間でデータを共有できるようにする共有コンテナ ID。

```swift
let coreConfig = ConfigParams.coreConfig(consumerID: "<obtained from server>")
let cardConfig = ConfigParams.cardConfig()

let card = ConfigParams.CardParams(cardID: "<obtained from server>",
        cardArt: UIImage(named: "<image_name>")!, productTitle: "<product title>", last4: "<last4>")
let walletExtensionConfig = ConfigParams.walletExtensionConfig(cardParamsList: [card],
        appGroupID: "<App Group ID defined in app capabilities>")

d1Task.configure([coreConfig, cardConfig, walletExtensionConfig]) { errors in
    if let errors = errors {
        for error in errors {
            // どの構成が失敗したかを特定するためにエラーを検査する
            // D1 SDK 統合のエラー管理セクションを参照してください
        }
    }
}

// Wallet 拡張フローで同じエンドユーザーを認証するために consumerId を保存する
saveToKeychain(key: "D1ConsumerID", value: "<consumer_ID>")

func saveToKeychain(key: String, value: String) {
    guard let valueData = value.data(using: .utf8) else {
        return
    }
    let query: [String: Any] = [kSecClass as String: kSecClassGenericPassword,
        kSecAttrService as String: "<service associated, e.g. IssuerAppService>",
        kSecAttrAccessGroup as String: "<App Group ID defined in app capabilities>",
        kSecAttrAccount as String: key]
    var addQuery = query
    addQuery[kSecValueData as String] = valueData
    let status = SecItemAdd(addQuery as CFDictionary, nil)

    if status == errSecDuplicateItem  {
        let updatedData: [String: Any] = [kSecValueData as String: valueData]
        SecItemUpdate(query as CFDictionary, updatedData as CFDictionary)
    }
}
```

**`issuerParamsList`**

複数の組み合わせの `issuerId` および `consumerId`:

* `issuerParamsList` をサポートする場合はこのバリアントを使用します – 一覧 `cardParamsList` と対応する `issuerId` および `consumerId`.
* `appGroupID` – D1 SDK がイシュアアプリケーションとその拡張機能の間でデータを共有できるようにする共有コンテナ ID。

```swift
let coreConfig = ConfigParams.coreConfig(consumerID: "<obtained from server>")
let cardConfig = ConfigParams.cardConfig()

var issuerParamsList: [ConfigParams.IssuerParams] = []
let card1 = ConfigParams.CardParams(cardID: "<obtained from server>",
        cardArt: UIImage(named: "<image_name>")!, productTitle: "<product title>", last4: "<last4>")
let card2 = ConfigParams.CardParams(cardID: "<obtained from server>",
        cardArt: UIImage(named: "<image_name>")!, productTitle: "<product title>", last4: "<last4>")
let card3 = ConfigParams.CardParams(cardID: "<obtained from server>",
        cardArt: UIImage(named: "<image_name>")!, productTitle: "<product title>", last4: "<last4>")
let issuerParam1 = ConfigParams.IssuerParams(cardParams: card1, issuerID: "<issuerId 1>", consumerID: "<consumerId 1>")
let issuerParam2 = ConfigParams.IssuerParams(cardParams: card2, issuerID: "<issuerId 2>", consumerID: "<consumerId 2>")
let issuerParam3 = ConfigParams.IssuerParams(cardParams: card3, issuerID: "<issuerId 2>", consumerID: "<consumerId 3>")
issuerParamsList.append(issuerParam1)
issuerParamsList.append(issuerParam2)
issuerParamsList.append(issuerParam3)

let walletExtensionConfig = ConfigParams.walletExtensionConfig(issuerParamsList: issuerParamsList,
        appGroupID: "<App Group ID defined in app capabilities>")

d1Task.configure([coreConfig, cardConfig, walletExtensionConfig]) { errors in
    if let errors = errors {
        for error in errors {
            // どの構成が失敗したかを特定するためにエラーを検査する
            // D1 SDK 統合のエラー管理セクションを参照してください
        }
    }
}

// Wallet 拡張の認証時に使用するために issuerId の値を保存する
saveToKeychain(key: "issuerID1", value: "<issuerId 1>")
saveToKeychain(key: "issuerID2", value: "<issuerId 2>")

func saveToKeychain(key: String, value: String) {
    guard let valueData = value.data(using: .utf8) else {
        return
    }
    let query: [String: Any] = [kSecClass as String: kSecClassGenericPassword,
        kSecAttrService as String: "<service associated, e.g. IssuerAppService>",
        kSecAttrAccessGroup as String: "<App Group ID defined in app capabilities>",
        kSecAttrAccount as String: key]
    var addQuery = query
    addQuery[kSecValueData as String] = valueData
    let status = SecItemAdd(addQuery as CFDictionary, nil)

    if status == errSecDuplicateItem  {
        let updatedData: [String: Any] = [kSecValueData as String: valueData]
        SecItemUpdate(query as CFDictionary, updatedData as CFDictionary)
    }
}
```

{% hint style="info" %}
次の使用を強く推奨します `last4` パラメータ。

なしでは `last4`SDK は共有デバイスのシナリオでトークン化の状態を誤解する可能性があります。例えば、ユーザー A がカードをトークン化し、その後同じデバイスでユーザー B が同じイシュアアプリケーションにログインした場合、SDK は誤ってユーザー B のトークン化が既に完了していると判断するかもしれません。
{% endhint %}

#### App Group ID

デフォルトでは、イシュアアプリケーションとその拡張機能はストレージを共有しません。app group を使用してそれらの間でストレージを共有してください。詳細は次を参照してください。 [Apple 拡張機能の概要](https://developer.apple.com/library/archive/documentation/General/Conceptual/ExtensibilityPG/ExtensionOverview.html) より詳しい情報。

`appGroupID` はイシュアアプリケーションとその拡張機能の間の共有コンテナを識別します。Xcode の次の設定で構成します **Capabilities**.

<figure><img src="/files/aae437b83c181202f0e0e1c55ef6a0fedf90f8fe" alt="Xcode configuration for app groups used by issuer application and extensions"><figcaption><p>イシュアアプリケーションとその拡張機能のために Xcode で app group を構成する例。</p></figcaption></figure>

{% hint style="info" %}
を使用する前に App Group ID が正しく Xcode に追加されていることを確認してください。 `configure(ConfigParams.walletExtensionConfig(...))`そうしないと、D1 SDK は次のエラーを返します `invalidAppGroupID` エラー。
{% endhint %}

#### Apple Pay 権限（entitlement）

アプリ内の Apple Pay プロビジョニングと同様に、UI と非 UI 拡張ターゲットの両方に次の権限を追加する必要があります `com.apple.developer.payment-pass-provisioning` オンボーディングの詳細については、Apple Wallet のプロビジョニングドキュメントまたは次を参照してください **ウォレット向けプッシュプロビジョニングのオンボーディング**.

#### UI 拡張

**UI 拡張を作成する**

<figure><img src="/files/d936929b2b254798e09ad8cd809a4d910ebdead2" alt="Xcode dialog for creating an intents UI extension"><figcaption><p>Apple Wallet の UI 拡張用に Xcode で Intents UI Extension ターゲットを作成します。</p></figcaption></figure>

{% stepper %}
{% step %}
Xcode に新しいターゲットを追加し、タイプを次に設定します **Intents UI Extension**.
{% endstep %}

{% step %}
新しいターゲットでは、イシュアアプリケーションと同じ App Group ID と権限の値を有効にします。App Group ID が異なる場合、 `login` API は次を返します `walletExtensionAppGroupIDNotFound` エラー。
{% endstep %}

{% step %}
拡張機能の Info.plist を更新する `次を設定します`:

* NSExtensionPointIdentifier `に` 設定します `com.apple.PassKit.issuer-provisioning.authorization`.
* NSExtensionPointIdentifier `NSExtensionPrincipalClass` に、次に準拠するクラスを設定します `D1IssuerProvisioningExtensionAuthorizationProviding`.
  {% endstep %}
  {% endstepper %}

例: 権限と拡張機能の構成:

```xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>com.apple.developer.payment-pass-provisioning</key>
    <true/>
    <key>com.apple.security.application-groups</key>
    <array>
        <string>group.com.example.IssuerApp</string>
    </array>
</dict>
</plist>
```

```xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>NSExtension</key>
    <dict>
        <key>NSExtensionPointIdentifier</key>
        <string>com.apple.PassKit.issuer-provisioning.authorization</string>
        <key>NSExtensionPrincipalClass</key>
        <string>$(PRODUCT_MODULE_NAME).IntentViewController</string>
    </dict>
</dict>
</plist>
```

**UI 拡張のために SDK を統合する**

D1 SDK は次の `D1IssuerProvisioningExtensionAuthorizationProviding` プロトコルを提供します。これは Apple の [`PKIssuerProvisioningExtensionAuthorizationProviding`](https://developer.apple.com/documentation/passkit/pkissuerprovisioningextensionauthorizationproviding) を拡張し、次の `login` API を追加します。

UI 拡張では、次に準拠するビューコントローラを実装し、エンドユーザーを認証して、を呼び出します `D1IssuerProvisioningExtensionAuthorizationProviding`D1 のアクセス トークン（例えばバックエンドからの JWT）を使用して。 `login` トークン生成についてはあなたの **SDK のログイン** ドキュメントを参照してください。

**単一の issuerId でログインする**

```swift
import UIKit
import PassKit
import D1

class IntentViewController: UIViewController, D1IssuerProvisioningExtensionAuthorizationProviding {
    var completionHandler: ((PKIssuerProvisioningExtensionAuthorizationResult) -> Void)?
    private let authButton = UIButton(type: .system)

    override func viewDidLoad() {
        super.viewDidLoad()
        // UI レイアウトを構成する
        authButton.addTarget(self, action: #selector(authButtonTouched), for: .touchUpInside)
    }

    @objc func authButtonTouched() {
        // キーチェーンから認証関連データを読み込む（少なくとも consumerID）
        let consumerID = loadFromKeychain(key: "D1ConsumerID")

        // Apple が要求するように手動および生体認証の両方を提供する

        // 認証に成功したら、このコンシューマーの D1 アクセストークンを取得する
        var issuerToken = getAccessToken(sub: consumerID!)

        // アクセストークンを使用して D1 ソリューションにログインする
        login(&issuerToken) { [weak self] error in
            if let _ = error {
                self?.completionHandler?(.canceled)
            } else {
                self?.completionHandler?(.authorized)
            }
        }
    }

    func loadFromKeychain(key: String) -> String? {
        let getQuery: [String: Any] = [kSecClass as String: kSecClassGenericPassword,
            kSecAttrService as String: "<service associated, e.g. IssuerAppService>",
            kSecAttrAccessGroup as String: "<App Group ID defined in app capabilities>",
            kSecAttrAccount as String: key,
            kSecReturnData as String: true]
        var item: AnyObject?
        let status = SecItemCopyMatching(getQuery as CFDictionary, &item)
        if status == errSecSuccess,
           let data = item as? Data {
            return String(data: data, encoding: .utf8)
        }
        return nil
    }

    func getAccessToken(sub: String) -> Data? {
        // Implement retrieval of the D1 access token for the given subject
        return Data()
    }
}
```

**複数の issuerIds でログイン**

```swift
import UIKit
import PassKit
import D1

class IntentViewController: UIViewController, D1IssuerProvisioningExtensionAuthorizationProviding {
    var completionHandler: ((PKIssuerProvisioningExtensionAuthorizationResult) -> Void)?
    private let authButton = UIButton(type: .system)

    override func viewDidLoad() {
        super.viewDidLoad()
        // UI レイアウトを構成する
        authButton.addTarget(self, action: #selector(authMultiIssuerButtonTouched), for: .touchUpInside)
    }

    @objc func authMultiIssuerButtonTouched() {
        // Keychain からイシュアIDを読み込む
        let issuerId1 = loadFromKeychain(key: "issuerID1")
        let issuerId2 = loadFromKeychain(key: "issuerID2")

        // Apple が要求するように手動および生体認証の両方を提供する

        // 認証に成功した後、各イシュアの D1 アクセストークンを取得する
        let issuerToken1 = getAccessToken(iss: issuerId1!)
        let issuerToken2 = getAccessToken(iss: issuerId2!)
        var issuerTokens = [issuerToken1, issuerToken2]

        // アクセストークンを使用して D1 ソリューションにログインする
        login(&issuerTokens) { [weak self] error in
            if let _ = error {
                self?.completionHandler?(.canceled)
            } else {
                self?.completionHandler?(.authorized)
            }
        }
    }

    func loadFromKeychain(key: String) -> String? {
        let getQuery: [String: Any] = [kSecClass as String: kSecClassGenericPassword,
            kSecAttrService as String: "<service associated, e.g. IssuerAppService>",
            kSecAttrAccessGroup as String: "<App Group ID defined in app capabilities>",
            kSecAttrAccount as String: key,
            kSecReturnData as String: true]
        var item: AnyObject?
        let status = SecItemCopyMatching(getQuery as CFDictionary, &item)
        if status == errSecSuccess,
           let data = item as? Data {
            return String(data: data, encoding: .utf8)
        }
        return nil
    }

    func getAccessToken(iss: String) -> Data {
        // 指定されたイシュアの D1 アクセストークンの取得を実装する
        return Data()
    }
}
```

{% hint style="info" %}
カードが同じ `issuerId` を共有するが、異なる `consumerId` 値を持つ場合、単一の `issuerToken を生成する` そのための `issuerId`.
{% endhint %}

#### 非 UI 拡張

**非 UI エクステンションを作成する**

<figure><img src="/files/d021a19d4ddf63170cbaa4127035ae93fe7b81ea" alt="Xcode dialog for creating an intents extension without UI"><figcaption><p>Apple Wallet の非 UI エクステンション用に Xcode で Intents Extension ターゲットを作成します。</p></figcaption></figure>

{% stepper %}
{% step %}
Xcode に新しいターゲットを追加し、タイプを次に設定します **Intents Extension**. クリア **UI エクステンションを含める** 以前に UI エクステンションが作成されているため。
{% endstep %}

{% step %}
新しいターゲットでは、イシュアアプリケーションと同じ App Group ID と権限値を有効にします。App Group ID が異なると、D1 SDK の操作は `walletExtensionAppGroupIDNotFound` エラー。
{% endstep %}

{% step %}
拡張機能の Info.plist を更新する `次を設定します`:

* NSExtensionPointIdentifier `に` 設定します `com.apple.PassKit.issuer-provisioning`.
* NSExtensionPointIdentifier `NSExtensionPrincipalClass` を拡張するクラスへ `D1IssuerProvisioningExtensionHandler`.
  {% endstep %}
  {% endstepper %}

例: 権限と拡張機能の構成:

```xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>com.apple.developer.payment-pass-provisioning</key>
    <true/>
    <key>com.apple.security.application-groups</key>
    <array>
        <string>group.com.example.IssuerApp</string>
    </array>
</dict>
</plist>
```

```xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>NSExtension</key>
    <dict>
        <key>NSExtensionPointIdentifier</key>
        <string>com.apple.PassKit.issuer-provisioning</string>
        <key>NSExtensionPrincipalClass</key>
        <string>$(PRODUCT_MODULE_NAME).IntentHandler</string>
    </dict>
</dict>
</plist>
```

**非 UI エクステンション向けに SDK を統合する**

D1 SDK は基底クラスを提供します `D1IssuerProvisioningExtensionHandler`、これは Apple の [`PKIssuerProvisioningExtensionHandler`](https://developer.apple.com/documentation/passkit/pkissuerprovisioningextensionhandler) を拡張し、必要な API を実装します。ほとんどの場合、このクラスを拡張するだけで済みます。

```swift
import D1

class IntentHandler: D1IssuerProvisioningExtensionHandler {
}
```

#### エラー処理

オプションで、 `errorEncountered(_:)` を非 UI エクステンションでオーバーライドして、エクステンションフロー中に受け取ったエラーをログまたは追跡できます。

```swift
import D1

class IntentHandler: D1IssuerProvisioningExtensionHandler {

    override func errorEncountered(_ error: D1Error) {
        print("Error = \(error.localizedDescription)")
    }
}
```

典型的なエラーケースには次のものが含まれます：

* The `appGroupID` は無効であるか見つかりません。
* D1 バックエンドがエラーを返します。

```console
# 例：status API のエラー
SDK Error = Error in status API. Cause: [2](-25300) Failed storage access. 
Error: [20009]The appGroupID is not found in Apple Pay Wallet UI and Non-UI extension. 
原因はいくつか考えられます：メインアプリケーションにウォレットエクステンションがない 
ConfigParams.configure(_:completion:) を呼び出して `D1Task.configure(_:completion:)` による構成を実行することで 
`ConfigParams.walletExtensionConfig(cardParamsList:appGroupID:)` または 
メインアプリケーションの機能で定義された appGroupID が UI と 
非 UI エクステンションのターゲット機能に定義されていません。

# 例：passEntries API のエラー
SDK Error = Error in passEntries API. Cause: [3]Received a server error with 
HTTP エラーコード 400 とメッセージ 'Server error' を受信しました。Error: [40001]カード操作の実行中にエラーが発生しました。 
カード操作を実行している間に発生したエラー。

# 例：remotePassEntries API のエラー
SDK Error = Error in remotePassEntries API. Cause: [3]Received a server error 
HTTP エラーコード 400 とメッセージ 'Server error' を受信しました。Error: [40001]エラーが発生しました 
カード操作を実行している間に発生したエラー。

# 例：generate API のエラー
SDK Error = Error in generate API. Cause: [3]Received a server error with 
HTTP エラーコード 400 とメッセージ '911. Operation failed .1' を受信しました。Error: [40001]エラーが発生しました 
カード操作を実行している間に発生したエラー。
```

#### Apple の機能要件

Apple の機能要件に合わせるため、D1 SDK `D1IssuerProvisioningExtensionHandler` とイシュアアプリケーションは次の慣行を採用します：

* カードデザインとカード所有者の名前を表示する。
* Apple が API を呼び出してから 100 ms 以内にカードが利用可能かどうか（有効性）を判断する。
* カードデザインとアプリアイコンは角が四角のものを提供する。
* UI エクステンションでの認証には手動ログインと生体認証の両方をサポートする。

### FAQ

<details>

<summary><strong>イシュアアプリケーションは、エンドユーザーがログインする前に Apple Wallet にカードの利用可能性をどのように提供できますか？</strong></summary>

エンドユーザーは少なくとも一度イシュアアプリケーションにログインする必要があります。そうすることでエクステンションはカードの状態で更新できます。イシュアアプリケーションは `configure(ConfigParams.walletExtensionConfig())` を呼び出して D1 SDK にカードのリストを提供します。

</details>

<details>

<summary><strong>ログインに失敗した場合、エラーはどこに表示されますか？</strong></summary>

ログインエラーは UI エクステンションのログイン画面に直接表示することを推奨します。UI エクステンションはイシュアアプリケーションのログインと同じ UX ガイドラインに従うべきです。

</details>

<details>

<summary><strong>カード画像のサイズと解像度の要件は何ですか？</strong></summary>

デジタルカード画像は Apple の機能要件に従うべきです：

* PNG（推奨）またはベクタ PDF として画像を提供する。
  * ウォレットエクステンションはメインアプリよりも厳しいメモリ制限があります。
  * PDF ファイルは OS がそれらを PNG に変換するためメモリ使用量を増やします。
* 解像度は 1536 × 969 を使用してください。
* 画像サイズが 4 MB 未満であることを確認してください。
* 角は丸めず四角（角が丸いものではない）を使用してください。
* 物理カード専用の要素（例：PAN、エンボス文字、ホログラム、チップ接点）を除外してください。
* 横向きの向きを使用してください。物理カードが縦向きの場合は横向きに再配置してください。
* NFC 支払いがサポートされている場合は、オプションでコンタクトレスインジケータを追加してください。

</details>

<details>

<summary><strong>エクステンションには新しいバンドル識別子が必要ですか？</strong></summary>

はい。新しいバンドル識別子は必ず `associatedApplicationIdentifier` に支払ネットワークオペレータ（PNO）によって含まれている必要があります。iOS はワイルドカードのバンドル識別子をサポートします。

イシュアは PNO API を使用して Apple Wallet 内の既存のパスも更新する必要があります。バンドル ID が含まれていない場合、Apple Wallet エクステンションを通じて追加されたカードはイシュアアプリケーションからアクセスできません（例：デジタル化状態の確認など）。

</details>

<details>

<summary><strong>イシュアアプリのアイコンが Apple Wallet に表示されない場合、何が問題でしょうか？</strong></summary>

次を確認してください：

* イシュアアプリがインストールされ、少なくとも一度開かれている。
* イシュアアプリケーションが `configure(ConfigParams.walletExtensionConfig())` を呼び出してカードリストを更新している。
* イシュアアプリケーションと両方のエクステンションが同じ `appGroupID` を `configure(ConfigParams.walletExtensionConfig())` と Xcode の機能で使用している。

</details>

<details>

<summary><strong>Apple Wallet エクステンションを動作させるためにアプリ内プロビジョニングは必要ですか？</strong></summary>

はい。イシュアアプリケーションは Apple Wallet エクステンションを追加する前に、まずウォレットへのアプリ内プッシュプロビジョニングを実装する必要があります。

</details>


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.payments.thalescloud.io/push-provisioning/ja/implement-push-provisioning/implement-push-to-digital-wallets/apple-wallet-extension.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
