> 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/nfc-wallet-sdk-android/ja/implement-nfc-wallet/make-payment/implement-contactless-payments/5.-perform-cdcvm-verification.md).

# 5. CDCVM検証を実行する

## 概要

非接触取引中、NFC Wallet SDK は次を要求する場合があります。 **エンドユーザー** CDCVM 検証を完了するために認証する必要があります。

あなたの **デジタルウォレットアプリケーション** この認証は、以前に設定した CDCVM メソッドを使用して実行する必要があります。参照: [CDCVM メソッドを設定する](/nfc-wallet-sdk-android/ja/implement-nfc-wallet/tokenize-a-card/set-cdcvm-method.md).

## SDK 連携

で認証を処理する `ContactlessPaymentServiceListener.onAuthenticationRequired()`。参照してください [非接触決済コールバックを実装する](/nfc-wallet-sdk-android/ja/implement-nfc-wallet/make-payment/implement-contactless-payments/2.-implement-contactless-payment-callbacks.md).

エンドユーザーを認証するには、SDK によって提供される `CHVerificationMethod` を使用します。これを使って次のものを取得します。 `DeviceCVMVerifier` インスタンス。その後、認証を開始し、次を使用して結果を監視します。 `DeviceCVMVerifyListener`.

`cvmResetTimeout` は、検証がどのくらいの時間有効かを示します。2 回目のタップを行うようエンドユーザーに案内する際に使用します。

### デバイスのキーロックを使用した CDCVM 検証

デバイスのキーロックを CDCVM メソッドとして使用する場合:

```java
//ContactlessPaymentServiceListener() の実装から
//...

@Override
public void onAuthenticationRequired(
  PaymentService activatedPaymentService,
  CHVerificationMethod cvm,
  long cvmResetTimeout) {

    // CDCVM の種類を確認
    if(cvm == CHVerificationMethod.DEVICE_KEYGUARD) {
        // キーロック認証画面を管理する実装済みの Activity を起動
        // この例では、その Activity は 'KeyguardActivity' と呼ばれます
        Intent intent = new Intent(getApplicationContext(), KeyguardActivity.class);
        intent.putExtra(Tags.CVM, cvm);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        startActivity(intent);
    }
}

//...
```

実装する `KeyguardActivity` をデジタルウォレットアプリケーション内で使用します。これは `DeviceCVMKeyguardActivity`を継承している必要があります。これにより、デバイス認証情報を使用した CDCVM 検証が有効になります。

以下の例では、次の実装を示します。 `KeyguardActivity` クラス:

{% code expandable="true" %}

```java
public class KeyguardActivity extends DeviceCVMKeyguardActivity{

     private static String TAG = KeyguardActivity.class.getName();
     private PaymentBusinessService paymentBusinessService;
     private DeviceCVMVerifier chDeviceCVMVerifier;
     private TextView message;
     private boolean keyguardVerificationStart = false;
     private CharSequence title;
     private CharSequence message1;

     @Override
     protected void onCreate(Bundle savedInstanceState) {

      Log.d(TAG, "KeyguardActivity:onCreate");
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_device_keyguard);
      Log.d(TAG, "KeyguardActivity:unlockAndWake : start");
      unlockAndWake();
      Log.d(TAG, "KeyguardActivity:unlockAndWake : end");

      title=getString(R.string.keyguard_title);
      message1=getString(R.string.keyguard_message);

      Bundle extras = getIntent().getExtras();

      // 渡された bundle から cvm オブジェクトを取得
      CHVerificationMethod cvm = (CHVerificationMethod) extras.getSerializable(Tags.CVM);

      message = (TextView) findViewById(R.id.message);

      paymentBusinessService = PaymentBusinessManager.getPaymentBusinessService();

      PaymentService paymentService = paymentBusinessService.getActivatedPaymentService();

      // cvm オブジェクトのおかげで、対応する DeviceCVMVerifier オブジェクトのインスタンスを取得
      chDeviceCVMVerifier = (DeviceCVMVerifier) paymentService.getCHVerifier(cvm);

      // 次に、対応するリスナーを DeviceCVMVerifier オブジェクトに設定
      chDeviceCVMVerifier.setDeviceCVMVerifyListener(new DeviceCVMVerifyListener() {

      @Override
      public void onVerifySuccess() {
         // 検証は OK でした!
         message.setText("");
         KeyguardActivity.this.finish();
     }


      @Override
      public void onVerifyError(int errorCode, CharSequence charSequence) {
          // 呼び出されることは想定していません
      }

      @Override
      public void onVerifyFailed() {
        // 検証は OK ではありません! ユーザーに再試行を求めます
        message.setText("認証できませんでした。もう一度お試しください。");
      }


      @Override
      public void onVerifyHelp(int i, CharSequence charSequence) {
          // 呼び出されることは想定していません
      }

      });

      cbDeviceCVMVerifier.setKeyguardActivity(this);

      // 画面が ON でロック解除されているときに認証を開始
      if (DeviceUtil.isDeviceScreenOn(getApplicationContext())) {

             Log.d(TAG, "デバイスのキーロック認証を開始");
             keyguardVerificationStart = true;
             DeviceCVMVerifierInput input = new  DeviceCVMVerifierInput(title,message1);
             chDeviceCVMVerifier.startAuthentication(input);
       } else {
             Log.d(TAG, "画面が無効化されているため、キーロック認証をスキップします");
       }

     }

}
```

{% endcode %}

### 生体認証を使用した CDCVM 検証（指紋の例）

デバイスが生体認証をサポートしている場合にこの方法を使用します（例では指紋を示しています）。

以下の例では、この仕組みをどのように実装できるかを示します。

```java
//ContactlessPaymentServiceListener() の実装から
//...

@Override
public void onAuthenticationRequired(
  PaymentService activatedPaymentService,
  CHVerificationMethod cvm,
  long cvmResetTimeout) {

    // CDCVM の種類を確認
    if(cvm == CHVerificationMethod.FINGERPRINT) {
        // 指紋認証画面を管理する activity を起動
        // この場合、この activity は 'BioFingerprintActivity' と呼ばれます
        Intent intent = new Intent(getApplicationContext(),
        BioFingerprintActivity.class);
        intent.putExtra(Tags.CVM, cvm);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        startActivity(intent);
    }
}

//...
```

専用の `Activity` を拡張する `DeviceCVMKeyguardActivity`を実装します。これにより、生体認証に失敗した場合にデバイスのキーロックへフォールバックできます。

{% code expandable="true" %}

```java
public class BioFingerprintActivity extends DeviceCVMKeyguardActivity {

    private static String TAG = BioFingerprintActivity.class.getName();
    private PaymentBusinessService paymentBusinessService;
    private DeviceCVMVerifier deviceCVMVerifier;
    private CancellationSignal cancellationSignal;
    private TextView message;
    private boolean isBioFPVerificationStarted = false;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_bio_fingerprint_2);
      unlockAndWake();
      Bundle extras = getIntent().getExtras();

      // bundle を通して渡された cvm オブジェクトを取得
      CHVerificationMethod cvm = (CHVerificationMethod) extras.getSerializable(Tags.CVM);

      message = (TextView) findViewById(R.id.message);
      paymentBusinessService = PaymentBusinessManager.getPaymentBusinessService();
      PaymentService paymentService = paymentBusinessService.getActivatedPaymentService();

      // cvm オブジェクトのおかげで 'DeviceCVMVerifier' のインスタンスを取得
      deviceCVMVerifier = (DeviceCVMVerifier) paymentService.getCHVerifier(cvm);

			// 対応するリスナーを設定
      deviceCVMVerifier.setDeviceCVMVerifyListener(new DeviceCVMVerifyListener() {

            @Override
            public void onVerifySuccess() {
              // 検証は OK です!
              message.setText("");
              BioFingerprintActivity.this.finish();
            }

            @Override
            public void onVerifyError(int errorCode, CharSequence charSequence) {

              Log.d(TAG, "BioFingerprintActivity:error :" + errorCode);

              // ロック画面モードでトリガーされた場合の特別なケース
              // FINGERPRINT_ERROR_CANCELED エラーが発生します
              if (errorCode == FingerprintManager.FINGERPRINT_ERROR_CANCELED) {
                  Log.d(TAG, "Fp を再起動");
                  if (cancellationSignal != null)
                      cancellationSignal.cancel();

              isBioFPVerificationStarted=true;
              cancellationSignal = new CancellationSignal();
              DeviceCVMVerifierInput input = new DeviceCVMVerifierInput(cancellationSignal);
              deviceCVMVerifier.startAuthentication(input);
              }
              // 通常のエラーコード処理
              else {
                        message.setText(charSequence + ". もう一度お試しください...");
                        if(errorCode == FingerprintManager.FINGERPRINT_ERROR_LOCKOUT) {
                            confirmCredential("キーロックによる検証", "試行回数が多すぎます。PIN / パターン / パスワードを使用して検証してください");
                  }
              }
            }

            @Override
            public void onVerifyFailed() {
                message.setText("指紋を認識できませんでした。もう一度お試しください。");
            }


            @Override
            public void onVerifyHelp(int i, CharSequence charSequence) {
                message.setText(charSequence + ". もう一度お試しください。");
            }

        });

        deviceCVMVerifier.setKeyguardActivity(this);
        cancellationSignal = new CancellationSignal();

        // 画面が ON でロック解除されているときに認証を開始
        if (DeviceUtil.isDeviceScreenOn(getApplicationContext())) {
            Log.d(TAG, "指紋認証を開始");
            DeviceCVMVerifierInput input = new DeviceCVMVerifierInput(cancellationSignal);
            deviceCVMVerifier.startAuthentication(input);
        } else {
            Log.d(TAG, "画面が無効化されているため、指紋認証をスキップします");
        }
    }

  	/* 指紋検証に失敗した場合、次のコールバックを実装することができます
    キーロック検証へフォールバックするためです。
    **/
    public void onKeyguardFallback(View v) {

      Log.d(TAG, "onKeyguardFallback");
      // deviceCVMVerifier.startAuthentication(input) を呼び出す


    }

  	@Override
  	public void onCancel(View v) {
      Log.d(TAG, "認証をキャンセル");
      cancelTransaction("取引はキャンセルされました。");
    }

    @Override
    public void onBackPressed() {
        Log.d(TAG, "onBackPressed()");
        cancelTransaction("取引はキャンセルされました。");
    }


    /*
    指紋の生体認証をキャンセルした後は、Payment サービスを無効化する必要があります
    **/
  	private void cancelTransaction(String message) {
          if (cancellationSignal != null) {
              cancellationSignal.cancel();
          }
          PaymentBusinessManager.getPaymentBusinessService().deactivate();
    }

}
```

{% endcode %}

デジタルウォレットアプリケーションがバックグラウンドに移った場合は、指紋認証の監視を停止します。

これは次のコードスニペットで実現できます。

```java
@Override
public void onResume() {
       super.onResume();
       cancellationSignal=new CancellationSignal();
       deviceCVMVerifier.startAuthentication(cancellationSignal);
   }

@Override
public void onPause() {
     if(cancellationSignal != null)
             cancellationSignal.cancel();
}
```

### ロック画面シナリオのサポート（任意）

デバイスがロックされているときの認証プロンプトをサポートする必要がある場合は、次を確認してください。

* 支払い中に表示される Activity は、 `showOnLockScreen=true`.
* ウェイクロックが取得され、ウィンドウフラグが設定されてロック画面上に UI を表示します。
* 次を解放してください。 `wakeLock` 支払い完了時にバッテリー使用量を抑えるためです。

manifest で次の設定を構成し、必要に応じてサンプルコードを実装してください。

```xml
<activity
        android:name=".BioFingerprintActivity"
        android:showOnLockScreen="true"
        android:screenOrientation="portrait" />
```

```java
@Override
public void onCreate() {
        //…
        unlockAndWake();
        //…
}

private void unlockAndWake() {

    PowerManager.WakeLock mWl;
    PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
    if (!pm.isScreenOn()) {
        mWl = pm.newWakeLock(
                PowerManager.SCREEN_BRIGHT_WAKE_LOCK | 
                PowerManager.FULL_WAKE_LOCK | 
                PowerManager.ACQUIRE_CAUSES_WAKEUP, "");
        mWl.acquire();
    }

    getWindow().addFlags(
            WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED | 
            WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON   | 
            WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON   | 
            WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
}

@Override
public void onDestroy() {

  try{
      if(null!=mW1){
          mWl.release();
      }
  }
 	catch(Exception e){ }
}
```

### 委任認証

委任認証を使うと、デジタルウォレットアプリケーションがエンドユーザーに認証を促し、その後、支払いを進めてよいことを SDK に通知できます。

この認証では、デバイスのキーロックまたは生体認証を使用して、ユーザー認証で保護された基盤の keystore を解除できます。

このフローは、支払い中に SDK が認証を要求した場合に適用されます。デジタルウォレットアプリケーションは次のいずれかを行えます。

* エンドユーザーに認証を促してから、 `DeviceCVMVerifier.onDelegatedAuthPerformed(timeOfAuth)`.
* 最近の成功した認証（設定された鍵の有効期間内）を再利用して、 `DeviceCVMVerifier.onDelegatedAuthPerformed(timeOfAuth)` すぐに呼び出します。

エンドユーザーが取引を中止した場合は、 `DeviceCVMVerifier.onDelegatedAuthCancelled()`.

```java
@Override
public void onAuthenticationRequired(final PaymentService service, CHVerificationMethod cvm, long cvmResetTimeout) {
                            
  // 生体認証またはキーロック方式にのみ適用
   if(cvm == CHVerificationMethod.BIOMETRICS || cvm == CHVerificationMethod.DEVICE_KEYGUARD){
      // verifier を取得
      final DeviceCVMVerifier verifier = (DeviceCVMVerifier)service.getCHVerifier(cvm);
                                
      // MPA は認証を実行し、認証のタイムスタンプを渡します
      ...

      // タイムスタンプは SDK が現在時刻と比較し、まだ Key-Validity-Duration 内であることを確認するために使用されます

      // 認証方式が生体認証の場合、MPA は CVM Type を FINGERPRINT に設定できます
      verifier.setCVMType(CVMType.FINGERPRINT);

      // また、取引の 2 回目のタップをエンドユーザーが行うための残り時間が十分にあるか確認することを、MPA に推奨します。
      verifier.onDelegatedAuthPerformed(timeOfAuth);
                                
      // ユーザーが認証を実行したくない場合、MPA は取引をキャンセルする必要があります
      verifier.onDelegatedAuthCancelled();
  }
}
```


---

# 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/nfc-wallet-sdk-android/ja/implement-nfc-wallet/make-payment/implement-contactless-payments/5.-perform-cdcvm-verification.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.
