Android SDK 시작하기

Android SDK를 시작하기 전에 기본 요건을 완료했는지 확인하세요.

Android SDK를 사용하면 Google 월렛에 패스를 추가할 수 있습니다. 앱에 Google 월렛 버튼을 추가하면 사용자가 Google 월렛에 패스를 추가하는 간단하면서도 재미있는 경험을 할 수 있습니다.

다음 단계에 따라 Android 애플리케이션에 Google 월렛 버튼을 추가합니다.

1. Passes 객체 만들기

참고: 패스 객체를 만들려면 패스 클래스가 필요합니다. 아직 패스를 만들지 않았다면 패스 클래스 만들기 방법에 대한 안내를 따릅니다. 다음 필수 속성을 포함하여 상응하는 GenericObject를 정의합니다.

  • classId: 기본 요건에서 생성된 패스 클래스 ID입니다.
  • id: 객체의 고유 ID입니다.

  • genericType: 카드가 속한 유형입니다. 카드가 사용 가능한 옵션과 일치하지 않으면 GENERIC_TYPE_UNSPECIFIED로 설정합니다.
  • cardTitle: 패스의 제목입니다.
  • header: 사용자 이름과 같은 패스의 헤더입니다.
또한 다음 속성을 포함하는 것이 좋습니다.
  • logo
  • subheader

이러한 속성이 일반 패스에 표시되는 방법에 관한 자세한 내용은 레이아웃 템플릿을 참고하세요.

다음은 일반 일반 샘플의 정의입니다.

JSON

      
{
  "id": "ISSUER_ID.OBJECT_ID",
  "classId": "ISSUER_ID.CLASS_ID",
  "genericType": "GENERIC_TYPE_UNSPECIFIED",
  "cardTitle": {
    "defaultValue": {
      "language": "en",
      "value": "Card title"
    }
  },
  "subheader": {
    "defaultValue": {
      "language": "en",
      "value": "Attendee"
    }
  },
  "header": {
    "defaultValue": {
      "language": "en",
      "value": "Alex McJacobs"
    }
  },
  "logo": {
    "sourceUri": {
      "uri": "https://storage.googleapis.com/wallet-lab-tools-codelab-artifacts-public/pass_google_logo.jpg"
    }
  }
}
      
    

2. 객체로 서명되지 않은 JWT 만들기

GenericObject가 생성되면 다음 스니펫과 같이 payload.GenericObjects 속성을 사용하여 서명되지 않은 JWT로 래핑합니다.

JSON

{
  "iss": "OWNER_EMAIL_ADDRESS",
  "aud": "google",
  "typ": "savetowallet",
  "iat": "UNIX_TIME",
  "origins": [],
  "payload": {
      "genericObjects": [ NEW_OBJECT ]
  }
}

3. UI에 Google 월렛 버튼 포함

Google 월렛은 애플리케이션에서 Google 월렛에 추가 과정을 트리거하는 데 사용할 수 있는 익숙한 버튼을 제공합니다. 버튼의 벡터 애셋은 버튼 가이드라인에서 확인할 수 있습니다.

Android 스튜디오의 File > New > Vector Asset 아래에서 벡터 애셋을 가져올 수 있습니다. 마법사에서 'Local file'을 선택하고 이름 (예: add_to_google_wallet_button.xml)를 클릭하고 로컬 드라이브에서 파일을 찾아 가져옵니다.

이제 가져온 드로어블을 사용하여 사용자 인터페이스에 버튼을 추가할 수 있습니다.

<ImageButton
    android:id="@+id/addToGoogleWalletButton"
    android:layout_width="match_parent"
    android:layout_height="48dp"
    android:minWidth="200dp"
    android:clickable="true"
    android:src="@drawable/add_to_google_wallet_button" />

버튼의 layout_height는 48dp이고 너비는 200dp 이상이어야 합니다.

4. 대상 기기에서 Google Wallet API를 사용할 수 있는지 확인

새 객체를 저장하기 전에 PayClient 클래스에서 getPayApiAvailabilityStatus 메서드를 호출하여 대상 기기에서 Google Wallet API를 사용할 수 있는지 확인합니다. 먼저 멤버를 활동에 추가하여 버튼을 표시하고 활동이 생성될 때 이를 인스턴스화합니다.

Kotlin

import com.google.android.gms.pay.PayClient

private lateinit var walletClient: PayClient

override fun onCreate(savedInstanceState: Bundle?) {
  super.onCreate(savedInstanceState)

  walletClient = Pay.getClient(this)

  // Additional logic in your onCreate method
}

Java

import com.google.android.gms.pay.PayClient;

private final PayClient walletClient;

@Override
protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);

  walletClient = Pay.getClient(application);

  // Additional logic in your onCreate method
}

이제 클라이언트를 사용하여 API를 사용할 수 있는지 확인합니다.

Kotlin

import com.google.android.gms.pay.PayApiAvailabilityStatus

private fun fetchCanUseGoogleWalletApi() {
  walletClient
    .getPayApiAvailabilityStatus(PayClient.RequestType.SAVE_PASSES)
    .addOnSuccessListener { status ->
      if (status == PayApiAvailabilityStatus.AVAILABLE) {
        // The API is available, show the button in your UI
      } else {
        // The user or device is not eligible for using the Pay API
      }
    }
    .addOnFailureListener {
      // Hide the button and optionally show an error message
    }
}

Java

import com.google.android.gms.pay.PayApiAvailabilityStatus;

private void fetchCanAddPassesToGoogleWallet() {
  walletClient
    .getPayApiAvailabilityStatus(PayClient.RequestType.SAVE_PASSES)
    .addOnSuccessListener(status -> {
      if (status == PayApiAvailabilityStatus.AVAILABLE) {
        // The API is available, show the button in your UI
      } else {
        // The user or device is not eligible for using the Pay API
      };
    })
    .addOnFailureListener(exception -> {
      // Google Play Services is too old, or API availability not verified
      // Hide the button and optionally show an error message
    });
}

마지막으로 API의 가용성을 확인해야 할 때 애플리케이션에서 위에 정의된 메서드를 호출합니다.

5. Google 월렛에 객체 추가

2단계의 서명되지 않은 JWT를 savePasses 메서드에 전달하여 GenericObject을 추가할 수 있습니다. Google 월렛 버튼을 클릭하여 추가 작업을 시작할 수 있습니다.

Kotlin

import android.os.Bundle
import android.view.View
import com.google.android.gms.samples.wallet.databinding.ActivityCheckoutBinding

private val addToGoogleWalletRequestCode = 1000

private lateinit var layout: ActivityCheckoutBinding
private lateinit var addToGoogleWalletButton: View

override fun onCreate(savedInstanceState: Bundle?) {
  super.onCreate(savedInstanceState)

  // Use view binding to access the UI elements
  layout = ActivityCheckoutBinding.inflate(layoutInflater)
  setContentView(layout.root)

  addToGoogleWalletButton = layout.addToGoogleWalletButton
  addToGoogleWalletButton.setOnClickListener {
    walletClient.savePasses(newObjectJson, this, addToGoogleWalletRequestCode)
  }

  // Additional logic in your onCreate method
}

Java

import android.os.Bundle;
import android.view.View;
import com.google.android.gms.samples.wallet.databinding.ActivityCheckoutBinding;

private static final int ADD_TO_GOOGLE_WALLET_REQUEST_CODE = 999;

private ActivityCheckoutBinding layout:
private View addToGoogleWalletButton;

@Override
protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);

  // Use view binding to access the UI elements
  layout = ActivityCheckoutBinding.inflate(getLayoutInflater());
  setContentView(layout.getRoot());

  addToGoogleWalletButton = layout.addToGoogleWalletButton;
  addToGoogleWalletButton.setOnClickListener(v -> {
    walletClient.savePasses(newObjectJson, this, ADD_TO_GOOGLE_WALLET_REQUEST_CODE);
  });

  // Additional logic in your onCreate method
}

savePasses 메서드는 저장 흐름을 트리거하고 저장 흐름이 완료된 후 onActivityResult 메서드를 호출합니다. onActivityResult의 구현은 다음과 유사합니다.

Kotlin

import android.content.Intent

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
  super.onActivityResult(requestCode, resultCode, data)

  if (requestCode == addToGoogleWalletRequestCode) {
    when (resultCode) {
      RESULT_OK -> {
        // Pass saved successfully
      }

      RESULT_CANCELED -> {
        // Save operation canceled
      }

      PayClient.SavePassesResult.SAVE_ERROR -> data?.let { intentData ->
        val errorMessage = intentData.getStringExtra(PayClient.EXTRA_API_ERROR_MESSAGE)
        // Handle error
      }

      else -> {
          // Handle unexpected (non-API) exception
      }
    }
  }
}

Java

import android.content.Intent;

@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
  super.onActivityResult(requestCode, resultCode, data);

  if (requestCode == ADD_TO_GOOGLE_WALLET_REQUEST_CODE) {
    switch (resultCode) {
      case RESULT_OK: {
        // Pass saved successfully
        break;
      }

      case RESULT_CANCELED: {
        // Save operation canceled
        break;
      }

      case PayClient.SavePassesResult.SAVE_ERROR: {
        if (data != null) {
          String apiErrorMessage = data.getStringExtra(PayClient.EXTRA_API_ERROR_MESSAGE);
          // Handle error
        }
        break;
      }

      default: {
        // Handle unexpected (non-API) exception
      }
    }
  }
}

패스가 성공적으로 추가되면 resultCode에는 Activity.RESULT_OK 값이 포함됩니다.

[테스트 전용] 패스

아직 데모 모드인 경우 생성한 모든 패스에는 패스 제목에 추가 텍스트 '[테스트 전용]'이 포함됩니다. 이는 데모 패스를 실시간 패스와 구별하기 위한 것입니다. 팀으로부터 프로덕션 승인을 받으면 사용자가 연결된 기기에서 월렛 앱을 다시 열 때 이러한 데모 모드 패스에 더 이상 텍스트가 표시되지 않습니다.

다음 단계