이번 글에서 설명하려고 하는 것을 간단히 정리하자면 Android 단말에서 AWS Mobile SDK를 이용하여 S3에 올려놓은 파일을 다운로드 하는 방법이다. 여기서는 다운로드에 대해서만 설명하지만 업로드 역시 같은 원리도 동작하므로 과정을 제대로 이해한다면 업로드도 간단하게 구현할 수 있을 뿐만 아니라 S3가 제공하는 여러가지 가능한 작업들에 대해서도 어렵지 않게 구현할 수 있다는 것을 알게 될 것이다. 그러므로 여기서는 다운로드에 대해서만 확실히 짚고 넘어가도록 하자.
먼저 전제적인 작업 과정을 간단히 설명하겠다.
- Cognito 서비스를 이용해서 "자격 증명 풀"을 생성한다.
- 생성된 "자격 증명 풀"에 S3에 접근할 수 있는 권한을 부여한다.
- 안드로이드에서 "자격 증명 풀"을 이용(인증을 수행)할 CredentialsProvider 객체와 S3에 파일을 송수신할 TransferUtility 객체를 생성한다.
- 다운로드를 실행한다.
보다시피 간단한 작업이지만 당장은 이해가 가지 않을 것이므로 하나 씩 살펴보도록 하자.
먼저 S3의 버킷은 이미 생성되어 있다고 가정하고 진행하도록 하겠다. 버킷 생성은 어려운 일도 아니거니와 관련 글도 쉽게 찾을 수 있으니 따로 설명은 하지 않겠다. 이 글에서는 "Bucket_Name"이라는 이름을 가진 버킷이 있다고 가정한다.
먼저 S3의 버킷은 이미 생성되어 있다고 가정하고 진행하도록 하겠다. 버킷 생성은 어려운 일도 아니거니와 관련 글도 쉽게 찾을 수 있으니 따로 설명은 하지 않겠다. 이 글에서는 "Bucket_Name"이라는 이름을 가진 버킷이 있다고 가정한다.
Cognito 자격 증명 풀 생성
AWS Management Console에 접속하여 Cognito 서비스 콘솔로 들어가도록 하자.
[그림1] Cognito 첫 화면 |
[그림2] 자격 증명 풀 만들기 - 1 |
[그림3] 자격 증명 풀 만들기 - 2 |
[그림4] 자격 증명 풀 만들기 완료 |
"AWS 자격 증명 얻기" 샘플 코드가 있다. 이 코드는 그대로 실제 코드에서 쓰이게 될 것이다. 참고로 이 화면은 언제든지 자격 증명 풀 상세화면에서 확인할 수 있으므로 특별히 관리를 위해서 따로 보관해야 할 필요는 없다.
이제 Cognito "자격 증명 풀 관리" 화면으로 가보면 아래와 같이 생성된 자격 증명 풀을 볼 수 있다.
[그림5] 자격 증명 풀 목록 화면 |
이것으로 Cognito 자격 증명 풀 생성은 끝났다. 이제 IAM으로 가서 설정을 계속하자.
IAM 역할 권한 설정
자격 증명 풀을 생성하고나면 자격 증명 풀이 사용하는 IAM 역할 2개가 생성된다. 이 역할에 S3 접근이 가능한 권한을 부여함으로써 앱 사용자들의 S3 접근을 가능토록 하는 것이다.
먼저 IAM 서비스 콘솔로 들어가도록 하자.
[그림6] IAM 콘솔 대시보드 |
[그림7] IAM 역할 목록 |
[그림8] 역할 상세 정보 |
[그림9] 인라인 정책 생성 |
먼저 대상 서비스는 S3이므로 "서비스"를 클릭하여 S3를 입력하도록 하자. 별로 설명할 게 없으므로 화면은 따로 넣지 않겠다.
다음 "작업"을 클릭하여 어떤 작업을 할 것인지 설정하도록 하자.
[그림10] 정책 작업 설정 |
[그림11] 대상 리소스 설정 |
[그림12] 대상 리소스 설정 |
[그림13] 정책 설정 완료 |
[그림14] 정책 검토 |
[그림15] 정책 설정 완료 |
AWS에서의 설정은 이것으로 완료되었다. Android 코드에서는 Cognito 인증만 정상적으로 수행된다면 S3에 접근할 수 있는 권한이 생기게 된다. 이제 Android 코드를 보도록 하자.
S3 Downlaod 구현
Android 소스코드는 Kotlin 으로 작성되었다. 혹시 Java로 작업중이더라도 조금만 자세히 들여다보면 대충 어떤 코드인지 알 수 있을 것이다. 위에서 설정중에 제공되는 샘플 코드는 Java 코드지만 붙여넣기를 하면 자동으로 변환될 것이므로 별로 문제 될 건 없다.
먼저 build.gradle 파일을 열어서 dependency를 추가하도록 하자.
... dependencies { ... implementation 'com.amazonaws:aws-android-sdk-mobile-client:2.13.5' implementation 'com.amazonaws:aws-android-sdk-cognito:2.13.5' implementation 'com.amazonaws:aws-android-sdk-s3:2.13.5' ... } ...
dependency 설정이 되었으면 다음으로 AndroidManifest.xml 파일에 몇 가지 설정을 해야 한다.
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" ...> ... <uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <application ...> <activity ... > ... </activity> <service android:name="com.amazonaws.mobileconnectors.s3.transferutility.TransferService" android:enabled="true" /> </application> ... </manifest>
위 예를 참고하여 AndroidManifest.xml 파일을 수정하도록 하자. 중요한 건 user-permission과 service 설정이다. user-permission은 network 작업과 storage 액세스를 위한 일반적인 것들이므로 안드로이드 개발자라면 당연히 알만한 것들이므로 따로 설명하진 않겠다. 주의해야 할 것은 service 설정이다. 파일 전송을 위해서 이 service 선언이 반드시 추가되어야 한다. 이름으로 봐선 전송작업을 background로 처리하기 위한 service인 것 같다. 실수로 빼먹었다가 크게 고생할 수 있으므로 신경써서 넣어주도록 하자.
class MainActivity : BaseActivity() { ... fun onDownloadClick(v: View) { downloadWithTransferUtility() } private fun downloadWithTransferUtility() { // Cognito 샘플 코드. CredentialsProvider 객체 생성 val credentialsProvider = CognitoCachingCredentialsProvider( applicationContext, "ap-northeast-2:167efb36-dea5-4724-935d-0c419fc48f12", // 자격 증명 풀 ID Regions.AP_NORTHEAST_2 // 리전 ) // 반드시 호출해야 한다. TransferNetworkLossHandler.getInstance(applicationContext) // TransferUtility 객체 생성 val transferUtility = TransferUtility.builder() .context(applicationContext) .defaultBucket("Bucket_Name") // 디폴트 버킷 이름. .s3Client(AmazonS3Client(credentialsProvider, Region.getRegion(Regions.AP_NORTHEAST_2))) .build() // 다운로드 실행. object: "SomeFile.mp4". 두 번째 파라메터는 Local경로 File 객체. val downloadObserver = transferUtility.download("SomeFile.mp4", File(filesDir.absolutePath + "/SomeFile.mp4")) // 다운로드 과정을 알 수 있도록 Listener를 추가할 수 있다. downloadObserver.setTransferListener(object : TransferListener { override fun onStateChanged(id: Int, state: TransferState) { if (state == TransferState.COMPLETED) { Log.d("AWS", "DOWNLOAD Completed!") } } override fun onProgressChanged(id: Int, current: Long, total: Long) { try { val done = (((current.toDouble() / total) * 100.0).toInt()) //as Int Log.d("AWS", "DOWNLOAD - - ID: $id, percent done = $done") } catch (e: Exception) { Log.d("AWS", "Trouble calculating progress percent", e) } } override fun onError(id: Int, ex: Exception) { Log.d("AWS", "DOWNLOAD ERROR - - ID: $id - - EX: ${ex.message.toString()}") } }) } }
MainActivity에 Download 버튼을 넣고 버튼을 클릭하면 다운로드를 수행하는 샘플코드이다. downloadWithTransferUtility() 함수가 전체 다운로드 코드를 담고 있으므로 이 함수를 자세히 보도록 하자.
가장 먼저 CredentialsProvider 객체를 생성한다. Cognito 자격 인증 풀을 생성할 때 제공되는 샘플코드를 붙여넣기 하면 된다.
다음으로 TransferUtility 객체를 생성한다. 버킷 이름과 S3 리전 정보를 적절히 입력하면 된다. 만약 접근 레벨을 설정할 때 모든 버킷을 대상으로 지정했다면 빈 문자열을 defaultBucket()에 지정하고 transferUtility.download()를 호출할 때 대상 객체(첫 번째 인자)를 "Bucket_Name/SomeFile.mp4"와 같이 설정해도 정상적으로 다운로드가 실행된다. 하지만 일반적으로는 다운로드할 파일이 있는 버킷을 지정하면 된다.
마지막으로 transferUtility.download() 함수를 호출하면 다운로드를 시작한다. 첫 번째 파라메터가 객체의 이름이고 두 번째 파라메터는 로컬에 다운로드할 경로의 File 객체이다. 이 함수는 TransferObserver 객체를 반환하는데 이 객체에 TransferListener를 추가하여 다운로드 이벤트 콜백을 받을 수 있다. 인터페이스의 함수 이름과 코드를 보면 대충 어떤 작업을 위한 것인지 알 수 있을 것이다.
이로써 S3에서 파일을 다운로드하는 방법에 대한 글을 마치도록 하겠다. 복잡한 느낌이 많이 들지만 각종 설정과 용어들 때문이지 결코 코드는 복잡하지 않다. 사실 이 글을 남기기로 한 이유도 얼마 안가서 다 잊어버릴 것 같은 느낌이 강하게 들었기 때문이다. 분명 이 과정을 반복하는 개발자들이 있을 것이다. 그 분들에게 많은 도움이 되었으면 한다.
0 개의 댓글:
댓글 쓰기