Kotiln 구현은 이쪽으로 <<
https://itstudy-mary.tistory.com/399?category=961265
코틀린에서는 상속을 받는 방식으로 구현해보았지만, 자바는 상속을 받지 않고 리스너를 정의해서 적용하는 방식으로 해보았다.
상속 구현은 코틀린에 있으니 그쪽과 비교해가면서 해보길 바란다.
그리고 자바에서는 인터페이스를 사용해보았다. 유틸이기 때문에 이 결제가 성공했는지 안했는지 콜백을 위한 인터페이스라고 봐도 무방하다.
public interface GooglepayJavaUtilDelegate {
void onSuccess();
}
private GooglepayJavaUtilDelegate GooglepayJavaUtilDelegate;
public GooglepayJavaUtil(@NotNull GooglepayJavaUtil.GooglepayJavaUtilDelegate GooglepayJavaUtilDelegate) {
this.GooglepayJavaUtilDelegate = GooglepayJavaUtilDelegate;
}
먼저 인터페이스를 구현한다.
인터페이스 작성 후 전역변수로 인터페이스를 선언하고 생성자를 이용해 외부에서 해당 인터페이스를 선언 해 전달할 수 있도록 한다. 이렇게 되면 필요한 액티비티에서 유틸 호출 시
GooglepayUtil.GooglepayUtilDelegate googlepayUtilDelegate = () -> ILog.iLogDebug(TAG, "onSuccess");
googlepayUtil = new GooglepayUtil(googlepayUtilDelegate);
해당 방식으로 인터페이스를 호출 후 오버라이딩 하여 인터페이스에 대한 동작을 구현할 수 있다.
먼저 전역변수를 선언한다.
이 때, 후에 쓰이게 될 업데이트(결제 후 서버 통신 콜백 매서드), 소비 완료 콜백 매서드를 담당할 리스너를 함께 선언해둔다.
private BillingClient billingCilent;
private List<ProductDetails> productDetailsList;
private GooglepayJavaUtilDelegate GooglepayJavaUtilDelegate;
//결제 완료 후 서버통신 콜백 매서드
private final PurchasesUpdatedListener purchaseUpdateListener = new PurchasesUpdatedListener() {
@Override
public void onPurchasesUpdated(@NonNull BillingResult billingResult, @Nullable @org.jetbrains.annotations.Nullable List<Purchase> list) {
if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK && list != null) {
for (Purchase purchase : list) {
DlogUtil.INSTANCE.d(TAG, "서버 통신 완료");
//소비로직(정합성 확인)
ConsumeParams consumeParams = ConsumeParams.newBuilder()
.setPurchaseToken(purchase.getPurchaseToken())
.build();
billingCilent.consumeAsync(consumeParams, consumeListenser);
}
}
}
};
//1회성 결제 아이템 소비콜백 매서드
private ConsumeResponseListener consumeListenser = (billingResult, s) -> {
if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) {
DlogUtil.INSTANCE.d(TAG, "소모 성공");
if(GooglepayJavaUtilDelegate != null) {
GooglepayJavaUtilDelegate.onSuccess();
}
} else {
DlogUtil.INSTANCE.d(TAG, "소모 실패");
}
};
UpdateListener의 경우 결제 화면이 내려가면 호출되는데, 이 부분은 서버통신에 대한 콜백만을 뱉기 때문에 후에 결제가 거부가 일어난다 하더라도 Response OK 를 내려버린다. 그렇기 때문에 소비로직은 1회성 제품을 소비시켜 지속적인 소비를 유도하는 것도 있지만 결제가 정상으로 일어났는지 consumeListener에서 정합성을 확인하는데에도 사용된다. 따라서, OK가 온다면 comsumeParma을 생성하여 내부에 결제토큰을 실어 소비를 시도한다. 이 결제가 거부되거나 Pending중이라면 해당 토큰이 소비되지 않을것이므로 consumeListener billingResult != 0이 리턴되며 에서 소모 실패를 반환한다.
구글 서버와의 통신을 담당하는 인터페이스부터 먼저 선언하자.
public void initBillingClient(Context context) {
billingCilent = BillingClient.newBuilder(context)
.setListener(purchaseUpdateListener)
.enablePendingPurchases()
.build();
billingCilent.startConnection(new BillingClientStateListener() {
@Override
public void onBillingServiceDisconnected() {
DlogUtil.INSTANCE.d(TAG, "연결 실패");
handleBillingClientDisconnection(context);
}
@Override
public void onBillingSetupFinished(@NonNull BillingResult billingResult) {
DlogUtil.INSTANCE.d(TAG, "연결 성공");
getPurchaseList();
}
});
consumeListenser = (billingResult, s) -> {
if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) {
DlogUtil.INSTANCE.d(TAG, "소모 성공");
if(GooglepayJavaUtilDelegate != null) {
GooglepayJavaUtilDelegate.onSuccess();
}
} else {
DlogUtil.INSTANCE.d(TAG, "소모 실패");
}
};
}
여기서 말하는 purchaseUpdatedListener은 앞서 선언한 서버 콜백 매서드이다.
인터페이스 설정이 끝나면 결제 빌드를 위한 결제 가능 목록을 호출한다. 여기서 불러온 데이터 중 중 원하는 상품으로 목록을 재설정하여 최종적으로 결제를 요청하게 된다(이 과정이 필요한 이유가.. 여기서 오는 콜백 자료형으로 결제 요청을 하기 때문입니다.)
private void getPurchaseList() {
List<QueryProductDetailsParams.Product> listParam = new ArrayList<>();
if(itemIdList.length > 0) {
for(String itemId : itemIdList) {
listParam.add(
QueryProductDetailsParams.Product.newBuilder()
.setProductId(itemId)
.setProductType(BillingClient.ProductType.INAPP)
.build()
);
}
} else {
DlogUtil.INSTANCE.d(TAG, "no list");
return;
}
QueryProductDetailsParams itemParam = QueryProductDetailsParams.newBuilder()
.setProductList(listParam)
.build();
billingCilent.queryProductDetailsAsync(itemParam, new ProductDetailsResponseListener() {
@Override
public void onProductDetailsResponse(@NonNull BillingResult billingResult, @NonNull List<ProductDetails> list) {
DlogUtil.INSTANCE.d(TAG, list);
productDetailsList = list;
}
});
}
먼저 우리가 사용할 구글인앱결제 id(콘솔에서 등록 하는 것이며, 콘솔에서 확인 가능합니다.)를 통해 Param의 제품을 빌드하고, 이 제품의 목록을 바탕으로 queryProductDetailAsync를 통해 리스트로 들어온 아이디에 부합하는 제품의 세부사항 리스트를 요청합니다.
billingResult == 0 --> billingClient.BillingResponseCode.OK와 동일하다면 리스트를 정상적으로 리턴합니다.
이제 이 리스트를 가지고 결제를 시도합니다.
public void callPay(@NotNull Activity activity, @NotNull String productId) {
List<BillingFlowParams.ProductDetailsParams> list = new ArrayList<>();
for(ProductDetails productDetail : productDetailsList) {
if(productDetail.getProductId().equals(productId)) {
BillingFlowParams.ProductDetailsParams productDetailsParams = BillingFlowParams.ProductDetailsParams.newBuilder()
.setProductDetails(productDetail)
.build();
list.add(productDetailsParams);
}
}
BillingFlowParams flowParams = BillingFlowParams.newBuilder()
.setProductDetailsParamsList(list)
.build();
billingCilent.launchBillingFlow(activity, flowParams);
}
먼저 제품의 DetailParams를 생성하여 리스트화 합니다. 이렇게 결제를 요청할 최종 리스트를 작성합니다.
그리고 BillingFlowParam을 통해 최종 결제를 요청합니다.
'Android > 안드로이드 스터디(JAVA)' 카테고리의 다른 글
JAVA] 안드로이드 진동 구현 (0) | 2023.01.19 |
---|---|
안드로이드 스튜디오 1. 기본 프로젝트 하나씩 변경해보기 (0) | 2020.07.28 |
안드로이드 시작하기를 위한 포스팅 모음 (0) | 2020.07.28 |