Created
March 15, 2024 01:03
-
-
Save DevHyeon0312/714c9890538812dd004fdbcd2fb0583b to your computer and use it in GitHub Desktop.
Android14 (SDK34) - OneUI 6.0 에서 발생하는 백화현상 임시 대응
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'package:flutter/material.dart'; | |
import 'package:flutter/services.dart'; | |
import 'package:get/get.dart'; | |
import 'package:iamport_flutter_example/screens/certification.dart'; | |
import 'package:iamport_flutter_example/screens/certification_result.dart'; | |
import 'package:iamport_flutter_example/screens/certification_test.dart'; | |
import 'package:iamport_flutter_example/screens/home.dart'; | |
import 'package:iamport_flutter_example/screens/payment.dart'; | |
import 'package:iamport_flutter_example/screens/payment_oneui_issue_test.dart'; | |
import 'package:iamport_flutter_example/screens/payment_result.dart'; | |
import 'package:iamport_flutter_example/screens/payment_test.dart'; | |
void main() { | |
runApp(IamportApp()); | |
} | |
class IamportApp extends StatefulWidget { | |
@override | |
_IamportAppState createState() => _IamportAppState(); | |
} | |
class _IamportAppState extends State<IamportApp> { | |
static const Color primaryColor = Color(0xff344e81); | |
@override | |
Widget build(BuildContext context) { | |
SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle( | |
systemNavigationBarColor: Colors.transparent, | |
statusBarColor: Colors.transparent, | |
)); | |
SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge); | |
return GetMaterialApp( | |
initialRoute: '/', | |
theme: ThemeData( | |
primaryColor: primaryColor, | |
), | |
getPages: [ | |
GetPage(name: '/', page: () => Home()), | |
GetPage(name: '/payment-test', page: () => PaymentTest()), | |
GetPage(name: '/payment', page: () => Payment()), | |
GetPage(name: '/payment-result', page: () => PaymentResult()), | |
GetPage( | |
name: '/payment-oneui-issue-test', | |
page: () => PaymentOneUiIssueTest(), | |
), | |
GetPage(name: '/certification-test', page: () => CertificationTest()), | |
GetPage(name: '/certification', page: () => Certification()), | |
GetPage( | |
name: '/certification-result', page: () => CertificationResult()), | |
], | |
); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'dart:io'; | |
import 'package:flutter/material.dart'; | |
import 'package:flutter/services.dart'; | |
import 'package:get/get.dart'; | |
import 'package:iamport_flutter/iamport_payment.dart'; | |
import 'package:iamport_flutter/model/payment_data.dart'; | |
class PaymentOneUiIssueTest extends StatefulWidget { | |
@override | |
State<PaymentOneUiIssueTest> createState() => _PaymentOneUiIssueTestState(); | |
} | |
class _PaymentOneUiIssueTestState extends State<PaymentOneUiIssueTest> | |
with WidgetsBindingObserver { | |
String userCode = Get.arguments['userCode'] as String; | |
PaymentData data = Get.arguments['data'] as PaymentData; | |
bool isLandscape = false; | |
@override | |
void initState() { | |
super.initState(); | |
WidgetsBinding.instance.addObserver(this); | |
} | |
@override | |
void dispose() { | |
WidgetsBinding.instance.removeObserver(this); | |
super.dispose(); | |
} | |
@override | |
void didChangeAppLifecycleState(AppLifecycleState state) async { | |
if (await _isSamsungIssueDevice()) { | |
if (state == AppLifecycleState.resumed) { | |
_showPortrait(); | |
} else if (state == AppLifecycleState.hidden) { | |
_shouldLandScape(); | |
} | |
} | |
} | |
Future<bool> _isSamsungIssueDevice() async { | |
if (Platform.isAndroid) { | |
/// DeviceInfoPlugin 을 사용하면 sdkIn 34, manufacturer samsung 일 경우에만 적용되도록 처리 가능합니다. | |
/// (모든 Android 기기에서 이슈에 대한 처리를 하는 것은 비효율적이기 때문입니다.) | |
// try { | |
// var androidInfo = await DeviceInfoPlugin().androidInfo; | |
// var sdkInt = androidInfo.version.sdkInt; | |
// var manufacturer = androidInfo.manufacturer; | |
// if (sdkInt == 34 && manufacturer == 'samsung') { | |
// return true; | |
// } | |
// } catch (_) {} | |
return true; | |
} | |
return false; | |
} | |
Future<void> _shouldLandScape() async { | |
SystemChrome.setPreferredOrientations([DeviceOrientation.landscapeLeft]); | |
Future.delayed(const Duration(milliseconds: 500), () { | |
setState(() { | |
isLandscape = true; | |
}); | |
}); | |
} | |
Future<void> _showPortrait() async { | |
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]); | |
Future.delayed(const Duration(milliseconds: 500), () { | |
setState(() { | |
isLandscape = false; | |
}); | |
}); | |
} | |
@override | |
Widget build(BuildContext context) { | |
return Stack( | |
children: [ | |
IamportPayment( | |
appBar: isLandscape | |
? null | |
: AppBar( | |
title: Text('아임포트 결제'), | |
centerTitle: true, | |
titleTextStyle: TextStyle( | |
fontSize: 24, | |
color: Colors.white, | |
), | |
backgroundColor: Colors.blue, | |
leading: IconButton( | |
icon: Icon(Icons.arrow_back_ios), | |
onPressed: () { | |
Get.back(); | |
}, | |
), | |
), | |
initialChild: SafeArea( | |
child: InitialChildWidget(), | |
), | |
userCode: userCode, | |
data: data, | |
callback: (Map<String, String> result) { | |
Get.offNamed('/payment-result', arguments: result); | |
}, | |
), | |
isLandscape ? InitialChildWidget() : SizedBox(), | |
], | |
); | |
} | |
} | |
class InitialChildWidget extends StatelessWidget { | |
@override | |
Widget build(BuildContext context) { | |
return Scaffold( | |
body: Center( | |
child: Column( | |
mainAxisAlignment: MainAxisAlignment.center, | |
children: [ | |
Image.asset('assets/images/iamport-logo.png'), | |
Padding(padding: EdgeInsets.symmetric(vertical: 15)), | |
Text('잠시만 기다려주세요...', style: TextStyle(fontSize: 20.0)), | |
], | |
), | |
), | |
); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'package:flutter/material.dart'; | |
import 'package:get/get.dart'; | |
import 'package:iamport_flutter/model/payment_data.dart'; | |
import 'package:iamport_flutter/model/pg/naver/naver_pay_products.dart'; | |
import 'package:iamport_flutter/model/pg/kcp/kcp_products.dart'; | |
import 'package:iamport_flutter_example/model/method.dart'; | |
import 'package:iamport_flutter_example/model/pg.dart'; | |
import 'package:iamport_flutter_example/model/quota.dart'; | |
class PaymentTest extends StatefulWidget { | |
@override | |
_PaymentTestState createState() => _PaymentTestState(); | |
} | |
class _PaymentTestState extends State<PaymentTest> { | |
final _formKey = GlobalKey<FormState>(); | |
late String userCode; // 가맹점 식별코드 | |
String pg = 'html5_inicis'; // PG사 | |
String payMethod = 'card'; // 결제수단 | |
String cardQuota = '0'; // 할부개월수 | |
late String vbankDue; // 가상계좌 입금기한 | |
late String bizNum; // 사업자번호 | |
bool digital = false; // 실물컨텐츠 여부 | |
bool escrow = false; // 에스크로 여부 | |
late String name; // 주문명 | |
late String amount; // 결제금액 | |
late String merchantUid; // 주문번호 | |
late String buyerName; // 구매자 이름 | |
late String buyerTel; // 구매자 전화번호 | |
late String buyerEmail; // 구매자 이메일 | |
final buttonStyle = ElevatedButton.styleFrom( | |
padding: EdgeInsets.symmetric(vertical: 10), | |
shape: RoundedRectangleBorder( | |
borderRadius: BorderRadius.circular(25), | |
), | |
elevation: 0, | |
shadowColor: Colors.transparent, | |
backgroundColor: Colors.blue, | |
); | |
final textStyle = TextStyle( | |
fontSize: 18, | |
color: Colors.white, | |
fontWeight: FontWeight.bold, | |
); | |
@override | |
Widget build(BuildContext context) { | |
return Scaffold( | |
appBar: AppBar( | |
title: Text('아임포트 결제 테스트'), | |
centerTitle: true, | |
titleTextStyle: TextStyle( | |
fontSize: 24, | |
color: Colors.white, | |
), | |
backgroundColor: Colors.blue, | |
leading: IconButton( | |
icon: Icon(Icons.arrow_back_ios), | |
onPressed: () { | |
Get.back(); | |
}, | |
), | |
), | |
body: SafeArea( | |
minimum: EdgeInsets.symmetric(horizontal: 15), | |
child: Form( | |
key: _formKey, | |
child: ListView( | |
children: [ | |
TextFormField( | |
decoration: InputDecoration( | |
labelText: '가맹점 식별코드', | |
), | |
validator: (value) => | |
value!.isEmpty ? '가맹점 식별코드는 필수입력입니다' : null, | |
initialValue: '', | |
onSaved: (String? value) { | |
userCode = value!; | |
}, | |
), | |
DropdownButtonFormField( | |
decoration: InputDecoration( | |
labelText: 'PG사', | |
), | |
value: pg, | |
onChanged: (String? value) { | |
setState(() { | |
pg = value!; | |
payMethod = Method.getValueByPg(value); | |
}); | |
}, | |
items: | |
Pg.getLists().map<DropdownMenuItem<String>>((String value) { | |
return DropdownMenuItem<String>( | |
value: value, | |
child: Text(Pg.getLabel(value)), | |
); | |
}).toList(), | |
), | |
DropdownButtonFormField( | |
decoration: InputDecoration( | |
labelText: '결제수단', | |
), | |
value: payMethod, | |
onChanged: (String? value) { | |
setState(() { | |
payMethod = value!; | |
}); | |
}, | |
items: Method.getListsByPg(pg) | |
.map<DropdownMenuItem<String>>((String value) { | |
return DropdownMenuItem<String>( | |
value: value, | |
child: Text(Method.getLabel(value)), | |
); | |
}).toList(), | |
), | |
payMethod == 'card' | |
? DropdownButtonFormField( | |
decoration: InputDecoration( | |
labelText: '할부개월수', | |
), | |
value: cardQuota, | |
onChanged: (String? value) { | |
setState(() { | |
cardQuota = value!; | |
}); | |
}, | |
items: Quota.getListsByPg(pg) | |
.map<DropdownMenuItem<String>>((String value) { | |
return DropdownMenuItem<String>( | |
value: value, | |
child: Text(Quota.getLabel(value)), | |
); | |
}).toList(), | |
) | |
: Container(), | |
payMethod == 'vbank' | |
? TextFormField( | |
decoration: InputDecoration( | |
labelText: '입금기한', | |
hintText: 'YYYYMMDDhhmm', | |
), | |
validator: (value) { | |
if (value!.isEmpty) return '입금기한은 필수입력입니다'; | |
if (value.length > 0) { | |
RegExp regex = RegExp(r'^[0-9]+$'); | |
if (!regex.hasMatch(value)) return '입금기한이 올바르지 않습니다.'; | |
} | |
return null; | |
}, | |
keyboardType: TextInputType.number, | |
onSaved: (String? value) { | |
vbankDue = value!; | |
}, | |
) | |
: Container(), | |
payMethod == 'vbank' && pg == 'danal_tpay' | |
? TextFormField( | |
decoration: InputDecoration( | |
labelText: '사업자번호', | |
), | |
validator: (value) { | |
if (value!.isEmpty) return '사업자번호는 필수입력입니다'; | |
if (value.length > 0) { | |
RegExp regex = RegExp(r'^[0-9]+$'); | |
if (!regex.hasMatch(value)) | |
return '사업자번호가 올바르지 않습니다.'; | |
if (value.length != 10) return '사업자번호는 10자리 숫자입니다.'; | |
} | |
return null; | |
}, | |
keyboardType: TextInputType.number, | |
onSaved: (String? value) { | |
bizNum = value!; | |
}, | |
) | |
: Container(), | |
TextFormField( | |
decoration: InputDecoration( | |
labelText: '주문명', | |
), | |
initialValue: '아임포트 결제 데이터 분석', | |
validator: (value) => value!.isEmpty ? '주문명은 필수입력입니다' : null, | |
onSaved: (String? value) { | |
name = value!; | |
}, | |
), | |
TextFormField( | |
decoration: InputDecoration( | |
labelText: '결제금액', | |
), | |
initialValue: '1000', | |
validator: (value) { | |
if (value!.isEmpty) { | |
return '결제금액은 필수입력입니다.'; | |
} | |
if (value.length > 0) { | |
RegExp regex = RegExp(r'^\d+(\.\d+)?$'); | |
if (!regex.hasMatch(value)) return '결제금액이 올바르지 않습니다.'; | |
} | |
return null; | |
}, | |
keyboardType: TextInputType.numberWithOptions(decimal: true), | |
onSaved: (String? value) { | |
amount = value!; | |
}, | |
), | |
TextFormField( | |
decoration: InputDecoration( | |
labelText: '주문번호', | |
), | |
validator: (value) => value!.isEmpty ? '주문번호는 필수입력입니다' : null, | |
initialValue: 'mid_${DateTime.now().millisecondsSinceEpoch}', | |
onSaved: (String? value) { | |
merchantUid = value!; | |
}, | |
), | |
TextFormField( | |
decoration: InputDecoration( | |
labelText: '이름', | |
), | |
initialValue: '홍길동', | |
onSaved: (String? value) { | |
buyerName = value!; | |
}, | |
), | |
TextFormField( | |
decoration: InputDecoration( | |
labelText: '전화번호', | |
), | |
initialValue: '01012341234', | |
validator: (value) { | |
if (value!.length > 0) { | |
RegExp regex = RegExp(r'^[0-9]+$'); | |
if (!regex.hasMatch(value)) return '전화번호가 올바르지 않습니다.'; | |
} | |
return null; | |
}, | |
keyboardType: TextInputType.number, | |
onSaved: (String? value) { | |
buyerTel = value!; | |
}, | |
), | |
TextFormField( | |
decoration: InputDecoration( | |
labelText: '이메일', | |
), | |
initialValue: 'example@example.com', | |
keyboardType: TextInputType.emailAddress, | |
onSaved: (String? value) { | |
buyerEmail = value!; | |
}, | |
), | |
Container( | |
padding: EdgeInsets.symmetric(vertical: 10), | |
child: Row( | |
children: [ | |
Expanded( | |
child: ElevatedButton( | |
onPressed: () { | |
if (_formKey.currentState!.validate()) { | |
_formKey.currentState!.save(); | |
print('creating payment data...'); | |
PaymentData data = PaymentData( | |
pg: pg, | |
payMethod: payMethod, | |
escrow: escrow, | |
name: name, | |
amount: num.parse(amount), | |
merchantUid: merchantUid, | |
buyerName: buyerName, | |
buyerTel: buyerTel, | |
buyerEmail: buyerEmail, | |
appScheme: 'flutterexample', | |
niceMobileV2: true, | |
); | |
if (payMethod == 'card' && cardQuota != '0') { | |
data.cardQuota = []; | |
if (cardQuota != '1') { | |
data.cardQuota!.add(int.parse(cardQuota)); | |
} | |
} | |
// 가상계좌의 경우, 입금기한 추가 | |
if (payMethod == 'vbank') { | |
data.vbankDue = vbankDue; | |
// 다날 && 가상계좌의 경우, 사업자 등록번호 10자리 추가 | |
if (pg == 'danal_tpay') { | |
data.bizNum = bizNum; | |
} | |
} | |
// 휴대폰 소액결제의 경우, 실물 컨텐츠 여부 추가 | |
if (payMethod == 'phone') { | |
data.digital = digital; | |
if (pg == 'danal') { | |
// 다날 && 휴대폰 소액결제의 경우, company 파라메터 추가 | |
data.company = '아임포트'; | |
} | |
} | |
// 정기결제의 경우, customer_uid 추가 | |
if (pg == 'kcp_billing') { | |
data.customerUid = | |
'cuid_${DateTime.now().millisecondsSinceEpoch}'; | |
} | |
// 네이버페이 관련 정보 추가 | |
if (pg == 'naverpay') { | |
NaverPayProducts p = NaverPayProducts( | |
name: '한국사', | |
categoryId: 'GENERAL', | |
categoryType: 'BOOK', | |
count: 10, | |
uid: '107922211', | |
payReferrer: 'NAVER_BOOK', | |
); | |
data.naverUseCfm = '20231026'; | |
data.naverCultureBenefit = false; | |
data.naverPopupMode = false; | |
data.naverProducts = [p]; | |
} | |
// kcp 에스크로 관련 정보 추가 | |
if (pg == 'kcp' && escrow == true) { | |
KcpProducts p = KcpProducts( | |
orderNumber: 'order1234', | |
name: '에스크로 주문', | |
quantity: 3, | |
amount: 5000, | |
); | |
data.kcpProducts = [p]; | |
} | |
// [이니시스-빌링.나이스.다날] 제공기간 표기 | |
data.period = { | |
'from': '20230101', | |
'to': '20231231', | |
}; | |
data.popup = false; | |
Get.toNamed( | |
'/payment', | |
arguments: { | |
'userCode': userCode, | |
'data': data, | |
}, | |
); | |
} | |
}, | |
child: Text( | |
'결제하기', | |
style: textStyle, | |
), | |
style: buttonStyle, | |
), | |
), | |
SizedBox( | |
width: 8, | |
), | |
Expanded( | |
child: ElevatedButton( | |
onPressed: () { | |
if (_formKey.currentState!.validate()) { | |
_formKey.currentState!.save(); | |
print('creating payment data...'); | |
PaymentData data = PaymentData( | |
pg: pg, | |
payMethod: payMethod, | |
escrow: escrow, | |
name: name, | |
amount: num.parse(amount), | |
merchantUid: merchantUid, | |
buyerName: buyerName, | |
buyerTel: buyerTel, | |
buyerEmail: buyerEmail, | |
appScheme: 'flutterexample', | |
niceMobileV2: true, | |
); | |
if (payMethod == 'card' && cardQuota != '0') { | |
data.cardQuota = []; | |
if (cardQuota != '1') { | |
data.cardQuota!.add(int.parse(cardQuota)); | |
} | |
} | |
// 가상계좌의 경우, 입금기한 추가 | |
if (payMethod == 'vbank') { | |
data.vbankDue = vbankDue; | |
// 다날 && 가상계좌의 경우, 사업자 등록번호 10자리 추가 | |
if (pg == 'danal_tpay') { | |
data.bizNum = bizNum; | |
} | |
} | |
// 휴대폰 소액결제의 경우, 실물 컨텐츠 여부 추가 | |
if (payMethod == 'phone') { | |
data.digital = digital; | |
if (pg == 'danal') { | |
// 다날 && 휴대폰 소액결제의 경우, company 파라메터 추가 | |
data.company = '아임포트'; | |
} | |
} | |
// 정기결제의 경우, customer_uid 추가 | |
if (pg == 'kcp_billing') { | |
data.customerUid = | |
'cuid_${DateTime.now().millisecondsSinceEpoch}'; | |
} | |
// 네이버페이 관련 정보 추가 | |
if (pg == 'naverpay') { | |
NaverPayProducts p = NaverPayProducts( | |
name: '한국사', | |
categoryId: 'GENERAL', | |
categoryType: 'BOOK', | |
count: 10, | |
uid: '107922211', | |
payReferrer: 'NAVER_BOOK', | |
); | |
data.naverUseCfm = '20231026'; | |
data.naverCultureBenefit = false; | |
data.naverPopupMode = false; | |
data.naverProducts = [p]; | |
} | |
// kcp 에스크로 관련 정보 추가 | |
if (pg == 'kcp' && escrow == true) { | |
KcpProducts p = KcpProducts( | |
orderNumber: 'order1234', | |
name: '에스크로 주문', | |
quantity: 3, | |
amount: 5000, | |
); | |
data.kcpProducts = [p]; | |
} | |
// [이니시스-빌링.나이스.다날] 제공기간 표기 | |
data.period = { | |
'from': '20230101', | |
'to': '20231231', | |
}; | |
data.popup = false; | |
Get.toNamed( | |
'/payment-oneui-issue-test', | |
arguments: { | |
'userCode': userCode, | |
'data': data, | |
}, | |
); | |
} | |
}, | |
child: Text( | |
'Android34-결제', | |
style: textStyle, | |
), | |
style: buttonStyle, | |
), | |
), | |
], | |
), | |
), | |
], | |
), | |
), | |
), | |
); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment