본문 바로가기
프로그래밍/Android

[Android Kotlin] RestAPI with Retrofit2

by Mr-후 2023. 3. 22.
반응형

어제, 오늘 양일간 나름 빠듯하게 안드로이드 앱 프로젝트를 진행했다. 
이 앱은 하이브리드 앱이라 네이티브 영역은 정말 0.5%정도 밖에 안된다. 나머지는 모두 웹에서 VueJs로 개발되어졌다. 
현업 요청으로 앱 버전 업데이트 정책을 고민해서 기능을 구현해달라는 요건이 있었으며, 웹페이지에서 입력한 아이디와 비밀번호를 기억할 수 있게 해 달라고 했다. 

하여, 진행된 개발업무는 다음과 같다.

  • 앱버전 체크 API연동을 위한 리소스 및 환경 구성
  • 네트워크 상태 체크 
  • 웹뷰 브릿지 구성 추가와 WebToApp, AppToWeb Interface개발 
  • 테스트 

 

오늘은 아무것도 없는 안드로이드 코틀린 앱 프로젝트에서 RestAPI와 통신하기 위해 Retrofit2를 이용하는 방법을 정리한다. 

우선 AndroidManifest.xml파일 안에 권한을 설정한다. 

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

두 개의 권한을 추가했다.
하나는 인터넷을 사용한다는 것이며,
또 하나는 현재 네트워크 상태를 체크하기 위해 추가하였다.
API통신을 하려면 아무래도 네트워크 상태를 체크해서 해야하니까. 

그리고 기존에는 없었던 IntroActivity(SplashActivity)를 추가했고 그 곳에서 프로그래시바를 돌리면서 네트워크 통신이 되도록 구성하였다. 

아직 AndroidManifest.xml파일이다. 

        <activity
            android:name=".IntroActivity"
            android:configChanges="orientation|keyboardHidden|screenSize"
            android:exported="true"
            android:label="@string/app_name"
            android:theme="@style/Theme.demo.Fullscreen">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

가장 먼저 화면에 나오도록 intent-filter의 IntroActivity로 옮겼다. 

다음으로는 build.gradle (Module :app) 에서 dependencies를 추가했다. 레트로핏2. 

    implementation 'com.squareup.retrofit2:retrofit:2.9.0'
    implementation 'com.squareup.retrofit2:converter-gson:2.9.0'

그리고 Sync Now

이제 프로젝트로 돌아와서, API로부터 받을 데이타 모델을 만들어야 한다. 

클래스 명은 VeersionCheck. 

data class VersionCheck(
    val code: Int,
    val `data`: Data,
    val dateTime: String,
    val message: String,
    val version: String
) {
    data class Data(
        val isForce: Boolean,
        val isUpdate: Boolean,
        val message: String,
        val version: String
    )
}

 

그리고 레트로핏을 사용하기 위한 서비스를 만들었다. 
클래스명은 WebServiceAPI. 

class WebServiceAPI {
    //객체를 하나만 생성하는 싱글톤 패턴을 적용
    companion object{
        private const val BASE_URL = "https://127.0.0.1/api/v1/app/"
        private var INSTANCE: Retrofit? = null

        fun getInstance(): Retrofit {
           if(INSTANCE == null) {
               INSTANCE = Retrofit.Builder().
               baseUrl(BASE_URL).addConverterFactory(GsonConverterFactory.create()).build()
           }
            return INSTANCE!!
        }
    }
}

 

버전 체크를 하기 위한 Interface를 생성해준다. 이곳에 각 기능별, 도메인별 API Interface를 추가해주면 될 것 같다. 

interface VersionCheckService {

    /**
     * 앱 버전 체크 API
     */
    @GET("versionCheck")
    fun getVersionInfo(
        @Query("platform") platform: String,
        @Query("version") version: String
    ): Call<VersionCheck>

}

레트로핏을 따로 또 공부를 해야겠지만, 우선 @GET으로 버전 정보를 보내고 업데이트가 있는지 데이터를 받아온다. 

 

이제 실제 사용하는 측면에서 보자면... 

    private fun checkVersion() {
        var platform: String = "A"
        val versionName = BuildConfig.VERSION_NAME
        val apiService = WebServiceAPI.getInstance().create(VersionCheckService::class.java)
        apiService.getVersionInfo(platform, versionName).enqueue(object : retrofit2.Callback<VersionCheck>{
            override fun onResponse(call: Call<VersionCheck>, response: Response<VersionCheck>) {
                progressBar!!.visibility = View.GONE

                val result = response.body()
                val versionInfo: VersionCheck.Data = result!!.data
                if (versionInfo.isUpdate) {
                    showUpdateAlertDialog(result)
                }
            }

            override fun onFailure(call: Call<VersionCheck>, t: Throwable) {
                TODO("Not yet implemented")
            }
        })
    }
    
    
    private fun showUpdateAlertDialog(versionInfo: VersionCheck) {
        AlertDialog.Builder(this)
            .setTitle("알림")
            .setMessage(versionInfo.data.message)
            .setPositiveButton("확인", object : DialogInterface.OnClickListener {
                override fun onClick(dialog: DialogInterface, which: Int) {
                    val intent = Intent(Intent.ACTION_VIEW, Uri.parse(appUpdateUrl))
                    startActivity(intent)
                    finish()
                }
            })
            .setNegativeButton("다음에 설치", object : DialogInterface.OnClickListener {
                override fun onClick(dialog: DialogInterface, which: Int) {
                    val intent = Intent(applicationContext, FullscreenActivity::class.java)
                    startActivity(intent)
                    finish()
                }
            })
            .setCancelable(false)
            .create()
            .show()
    }

두 개의 버튼이 있는 알럿다이얼로그가 뜨는데, 확인을 누르면 다운로드 사이트로 이동하고 다음에 설치를 누르면 메인으로 이동하게 처리하였다. 

setCancelable(false)를 주면 뒤로가기 버튼과 팝업영역 외에 터치할 경우도 팝업이 사라지지 않도록 한다. 

 

Swift에서는 MVVM 패턴을 적용해서 한다고 했는데, 안드로이드는 그기까지는 가지 못했고 단순하게 통신을 하고 결과만 받아서 화면 분기 처리를 하도록 하였다. 

다음번에는 안드로이드 앱에서 네트워크 상태 체크 방법에 대해서 정리해서 올린다. 

반응형