반응형
저번 이야기에서는 인앱 결제를 다루어보았다면, 저의 2번째 업무이었던 정기 결제에 대해 리뷰해보록 하겠습니다.
상품 등록은 이전 포스트에 있는 등록 방식에서 정기 결제 상품을 등록하면 됩니다. ~
정기 결제 상품 같은 경우 상품들에 대해 인앱 결제 상품과 달리 그룹 id를 통해 관리하니 그 부분만 알고 계시면 금방하실 수 있을 것입니다.
만약 인앱 상품 결제가 궁금하시다면 이전 포스트를 보고 오세요~
2024.02.18 - [코딩/Flutter] - [flutter] 인앱 결제 iOS & Android
정기 결제를 구현 하기 위해서는 아래와 같은 기능이 필요합니다.
- 정기 결제 상품들 읽어오기
- 결제 기능
- 결제 후 서버에 구매 요청 기능
- 완료시 로직
아래 코드를 통해 우린 확인할 수 있을 것이다.
import 'package:flutter/material.dart';
import 'package:in_app_purchase/in_app_purchase.dart';
import 'package:intl/intl.dart';
class SubscribePage extends StatefulWidget {
const SubscribePage({Key? key}) : super(key: key);
@override
State<SubscribePage> createState() => _SubscribePageState();
}
class _SubscribePageState extends State<SubscribePage> {
final InAppPurchase _iap = InAppPurchase.instance;
List<ProductDetails> _products = [];
String productId = "";
@override
void initState() {
super.initState();
_loadProducts(); // 상품 정보 출력
_listenToPurchaseUpdated(); // 구매 업데이트 감지
}
// 상품 정보를 불러오는 함수
void _loadProducts() async {
const Set<String> kIds = {정기 상품 결제의 그룹 id};
final ProductDetailsResponse response =
await _iap.queryProductDetails(kIds);
if (response.notFoundIDs.isEmpty) {
setState(() {
_products = response.productDetails;
});
}
}
// 상품 구매 함수
void _buyProduct(ProductDetails product, String productID) {
productId = productID;
print("선택한 id : " + productId);
final purchaseParam = PurchaseParam(productDetails: product);
_iap.buyNonConsumable(purchaseParam: purchaseParam);
}
// 구매 업데이트 감지 함수
void _listenToPurchaseUpdated() {
final purchaseUpdated = _iap.purchaseStream;
purchaseUpdated.listen((purchaseDetailsList) {
purchaseDetailsList.forEach((purchaseDetails) async {
if (purchaseDetails.status == PurchaseStatus.pending) {
// 구매 진행중
print("구독 구매 진행중");
} else {
if (purchaseDetails.status == PurchaseStatus.error) {
// 구매 오류 발생시
print("구독 구매 오류 발생");
} else if (purchaseDetails.status == PurchaseStatus.purchased) {
// 구매 성공
if (purchaseDetails.pendingCompletePurchase) {
bool isVerified = await _verifyPurchase(
productId, purchaseDetails);
await _iap.completePurchase(purchaseDetails);
print("구독 구매 완료");
}
}
}
});
});
}
// 서버에 구매 검증 요청
Future<bool> _verifyPurchase(
String productId, PurchaseDetails purchaseDetails) async {
// 플랫폼 확인
String platform =
Theme.of(context).platform == TargetPlatform.iOS ? 'apple' : 'google';
// POST 데이터
Map<String, dynamic> purchaseData = {
'platform': platform,
};
// 플랫폼에 따라 필요한 데이터를 추가
if (platform == 'apple') {
purchaseData['encoded_receipt_data'] =
purchaseDetails.verificationData.localVerificationData;
} else if (platform == 'google') {
purchaseData['product_id'] = productId;
purchaseData['purchase_token'] = purchaseDetails.purchaseID;
}
// Django Post
try {
// 서버에 요청 로직을 추가하시면 됩니다.
// 구매 완료 Alert Dialog
showPurchaseCompleteDialog(context, Intl.message('success'));
return true;
} catch (e) {
showPurchaseCompleteDialog(context, Intl.message('fail'));
return false;
}
}
// 구매 완료 알림창
void showPurchaseCompleteDialog(BuildContext context, String text) {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text("${Intl.message('pay')}$text"),
actions: <Widget>[
ElevatedButton(
child: Text(Intl.message('ok')),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
},
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('구독 결제 페이지'),
),
body: _products.isEmpty
? const Center(child: CircularProgressIndicator())
: ListView.builder(
itemCount: _products.length,
itemBuilder: (_, index) => ListTile(
title: Text(_products[index].title),
subtitle: Text(_products[index].price),
trailing: ElevatedButton(
child: const Text('구매하기'),
onPressed: () =>
_buyProduct(_products[index], _products[index].id),
),
),
),
);
}
}
반응형
'코딩 > Flutter' 카테고리의 다른 글
Flutter Dialog 요소들 배경 투명하게 만들기 (4) | 2024.06.09 |
---|---|
Flutter 백그라운드 알림 (Cloud Messaging) (4) | 2024.03.03 |
[flutter] 인앱 결제 iOS & Android (0) | 2024.02.18 |
[Flutter] Factory constructors (3) | 2023.11.06 |
[Flutter] flutter 버전 업그레이드 오류 뜰 때 (0) | 2022.10.31 |