원본출처: 티스토리 바로가기
지난 포스팅에 연속해서
https://billcorea.tistory.com/267
구동되는 이야기는 지난 포스팅에 적었습니다. 참고하시면 될 것 같고요. 오늘은 그것들을 구현하기 위해 했던 코드 구현에 대해서 이야기해 보겠습니다.
HTTP 통신은
일반적으로 API 통신은 HTTP 을 이용해서 호출하라고 합니다. 이번에 사용했던 PAYAPP의 경우에도 동일합니다. 이런 경우 안드로이드에서는 통신과 관련된 몇 가지 해야 할 부분들이 있습니다.
먼저 manifest 에서의 권한 설정 부분이 필요합니다.
<uses-permission android:name="android.permission.INTERNET" />
인터넷 사용에 대한 권한을 등록합니다. 다음은 통신의 하는 경우 네트워크와 관련해서는
<application ... android:usesCleartextTraffic="true" ... > <activity android:name=".MainActivity" android:exported="true" ...
개발자 가이드에서 알려주고 있는 것과 같이 네트워크 트래픽에 대한 설정을 true로 해 주어야 합니다.
그다음 요구되는 사항은 http connect을 맺거나 하는 경우 비동기 설정을 해 주어야 하는 부분이 있습니다. 그래서 구글링을 해보면 여러 가지 방법들이 설명이 되어 있습니다. thread을 이용하여 하거나 그 외 다른 비동기 통신 방법을 구현하고 설명합니다.
https://ktor.io/
이번에는 Ktor 방식을 이용한 비동기 통신을 구현해 보기로 했습니다.
gradle 파일 설정
gradle 파일에는 아래와 같이 ktor을 사용하기 위해서 implementaion을 설정했습니다. 2022.10.20 쯤에는 2.1.2 버전이 최신 버전이라고 되어 있습니다.
//ktor implementation "io.ktor:ktor-client-core:2.1.2" implementation "io.ktor:ktor-client-cio:2.1.2" implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4' implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4'
Helper 구현하기
먼저 통신을 위한 helper 을 구현해 봅니다.
import android.util.Log import io.ktor.client.* import io.ktor.client.engine.cio.* import io.ktor.client.request.* import io.ktor.client.statement.* import io.ktor.http.* import io.ktor.util.date.* import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext class HttpRequestHelper { companion object { val TAG: String = HttpRequestHelper::class.java.name } private val client: HttpClient = HttpClient(CIO) /** * https://api.payapp.kr/oapi/apiLoad.html * * cmd=payrequest&userid=payapptest&goodname=testGood&price=1000&recvphone=01055559999&smsuse=n * */ suspend fun requestKtorIoInDetail(): String = withContext(Dispatchers.IO) { // set HttpRequestBuilder val response: HttpResponse = client.request("https://api.payapp.kr/oapi/apiLoad.html") { method = HttpMethod.Post headers { append("Content-Type", "application/x-www-form-urlencoded") } parameter("cmd","payrequest") parameter("userid","payapptest") parameter("goodname","testGood") parameter("price","1000") parameter("recvphone","01055559999") parameter("smsuse","n") } val responseStatus = response.status Log.d(TAG, "requestKtorIo: $responseStatus") if (responseStatus == HttpStatusCode.OK) { response.bodyAsText() } else { "error: $responseStatus" } } }
개발자 가이드에서 말하는 것처럼 thread을 지원하여 사용자는 앱이 멈춤을 느끼지 않도록 하고 비동기 통신을 이용하여 목적에 필요한 자료를 전송하고 결과를 수집할 수 있습니다.
https://developer.android.com/kotlin/coroutines-adv?hl=ko
payapp 결제 연동
payapp api 가이드에서 설명하는 결제 연동 페이지로의 호출 부분은 위 예시된 코드와 같이 url을 호출하면 됩니다. 이번에 구현하고자 하는 앱의 경우는 결제 연동만 일단 구현해 볼 요량이므로 위 코드와 같이 구현하고, 관련된 정보를 추가로 파라미터로 전송하여 결제 연동을 위한 QRcode 이미지를 webView에 보여주는 방식으로 진행하고 있습니다.
파라미터 | 전달 값 |
cmd | payrequest (고정값 : 결제 요청시 사용) |
userid | payapp 에 판매 회원으로 가입한 id |
goodname | 판매하는 상품명칭 |
price | 가격 |
recvphone | 결과를 수신받을 휴대전화번호 |
smsuse | sms 사용여부 |
위 정도는 필수값이고 그 외에도 다른 항목들이 있지만 그것은 API 문서를 참조하여 보시기 바랍니다. 이번 앱 구현에서는 이 정도만 있어도 됩니다.
MainActivity에서 사용
class MainActivity : ComponentActivity() , CoroutineScope { ..... private lateinit var job: Job override val coroutineContext: CoroutineContext get() = Dispatchers.Main + job ... override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) sp = getSharedPreferences(packageName, MODE_PRIVATE) job = Job() // CoroutineScope를 위해 job을 할당 ... } ..... private fun doPunched(destinationsNavigator: DestinationsNavigator) { var errno = "" var qrUrl = "" launch(Dispatchers.Main) { val result = HttpRequestHelper().requestKtorIoInDetail() val decoded = URLDecoder.decode(result, "UTF-8") var lineItems = decoded?.split("&") if (lineItems != null) { for (line in lineItems) { Log.e("", "${line}") if (line.indexOf("errno") > -1) { errno = line.split("=")[1] } if (line.indexOf("qrurl") > -1) { qrUrl = line.split("=")[1] } } } Log.e(TAG, "${qrUrl} ${errno}") if (!"".equals(qrUrl)) { doWebView(qrUrl, destinationsNavigator) } } } ..... fun doFinish() { job.cancel() // 종료 되게... finish() }
mainActivity에서 다른 구현이 많이 있기는 하겠지만, 코루틴 사용을 위해서 Job을 선언하는 부분 등 필요한 부분만 나열을 하였으니 코드 구현 시 참고하셔야 합니다. 위 예시 코드와 같이 launch 구문을 이용해서 위에서 작성한 helper을 호출하면 결과 값이 string으로 돌아오기 때문에 그 값을 파싱 해서 qrurl 부분만 값으로 받아오고 그 값을 전달해서 webview에 표시하는 것으로 구현은 마무리가 됩니다.
@Composable fun Url2WebView( qrUrl : String, doBackQRCode:() -> Unit ){ val fontFamily = FontFamily(Font(R.font.poorstory_regular, FontWeight.Normal)) Column( modifier = Modifier .fillMaxSize() .padding(20.dp), verticalArrangement = Arrangement.Center, horizontalAlignment = Alignment.CenterHorizontally ) { Row( modifier = Modifier.padding(2.dp), horizontalArrangement = Arrangement.End, verticalAlignment = Alignment.CenterVertically ) { IconButton(onClick = { doBackQRCode() }) { Icon( imageVector = Icons.Outlined.ArrowBack, contentDescription = "ArrowBack", tint = softBlue ) } Text(text = stringResource(id = R.string.msgPunchedQRCode), style = TextStyle( fontWeight = FontWeight.Bold, color = softBlue, fontSize = 24.sp, fontFamily = fontFamily )) } // Adding a WebView inside AndroidView // with layout as full screen AndroidView(factory = { WebView(it).apply { layoutParams = ViewGroup.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT ) webViewClient = WebViewClient() loadUrl(qrUrl) } }, update = { it.loadUrl(qrUrl) }) } }
이제 앱이 잘 구현 되기를 바라면 글을 정리해 보겠습니다.
댓글
댓글 쓰기