지난 포스팅에 연속해서
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)
})
}
}
이제 앱이 잘 구현 되기를 바라면 글을 정리해 보겠습니다.
'모바일 앱(안드로이드)' 카테고리의 다른 글
개발일기 #6 메뉴판 구성을 위해서 TabLayout 만들어 보기 (0) | 2022.10.26 |
---|---|
안드로이드 앱 만들기 : 구글 인앱 결제 쉽게 따라하기 (정기결제, 소스공유) (13) | 2022.10.22 |
개발일기 #5 PAYAPP 연동을 위한 준비 (0) | 2022.10.20 |
개발일기 #4 dialog box 쉽게 만들어 보기 (2) | 2022.10.12 |
개발일기 #3 : jetpack compose 숫자 전용 입력 받기 (0) | 2022.10.08 |