registerForActivityResult(), Firebase Storage를 활용해 이미지 업로드 하기

KEH·2021년 7월 19일
0
post-thumbnail

앱에서 이미지를 가져와 게시글을 업로드할 때 registerForActivityResult()와 Firebase Storage를 사용하였다.

갤러리 이동 -> registerForActivityResult

네비게이션 메뉴바에서 카메라 메뉴탭을 누르면 갤러리로 이동하는 과정에서 registerForActivityResult() 메서드를 사용했다.

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

<application
   ...

우선 앱이 자신의 핸드폰 갤러리에 접근하는 것을 허용하는지 사용자에게 묻기 위해 AndroidManifest.xml 파일에 READ_EXTERNAL_STORAGE 권한을 추가한다.

class MainActivity : AppCompatActivity() {

    ...
    
    //갤러리 앱으로 이동하는 launcher 등록
    private var launcher = registerForActivityResult(ActivityResultContracts.GetContent()) {
            it-> changeFragment(GalleryFragment(it))
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        ...
        
        initNavigationBar() //네이게이션 바의 각 메뉴 탭을 눌렀을 때 화면이 전환되도록 하는 함수.

        //앱에서 앨범에 접근을 허용할지 선택하는 메시지, 한 번 허용하면 앱이 설치돼 있는 동안 다시 뜨지 않음.
        ActivityCompat.requestPermissions(this@MainActivity,
            arrayOf(android.Manifest.permission.READ_EXTERNAL_STORAGE), 1)
    }
    
    fun initNavigationBar() {
        binding.myNavigation.run {
            setOnNavigationItemSelectedListener {
                when (it.itemId) {
                
                    ...
                    
                    R.id.photoItem -> {
                        //앱이 갤러리에 접근햐는 것을 허용했을 경우
                        if (ContextCompat.checkSelfPermission(this@MainActivity.applicationContext, android.Manifest.permission.READ_EXTERNAL_STORAGE)== PackageManager.PERMISSION_GRANTED) {
                            launcher.launch("image/*")  //갤러리로 이동하는 런처 실행.
                        } else {    //앱이 갤러리에 접근햐는 것을 허용하지 않았을 경우
                            Toast.makeText(this@MainActivity,
                                "갤러리 접근 권한이 거부돼 있습니다. 설정에서 접근을 허용해 주세요.",
                                Toast.LENGTH_SHORT).show()
                        }
                    }
                    
                    ...
                    
                true
            }
            selectedItemId = R.id.homeItem
        }
    }
}
  1. registerForActivityResult() 메서드를 호출해 갤러리 앱으로 이동하는 launcher를 등록한다.

    Contract는 ActivityResultContracts에 이미 정의돼 있는 GetContent()를 사용하면 갤러리로 이동할 수 있다. 갤러리 앱에서 다시 돌아올 때 전달받는 데이터(it)는 사용자가 선택한 이미지의 uri이다. 이 uri와 함께 GalleryFragment로 이동한다.

  2. ActivityCompat.requestPermissions() 메서드를 호출해 처음 MainActivity 화면에 들어온 사용자에게 앨범에 접근해도 될지 권한을 요청하는 READ_EXTERNAL_STORAGE 메세지를 보낸다.

  3. 메뉴바에서 카메라탭을 클릭했을 때 갤러리 앱으로 이동하는 launcher를 실행한다.

    ContextCompat.checkSelfPermission()으로 사용자가 권한을 허용했는지 확인한 후 권한을 허용했다면 launcher를 실행한다.

Firebase Storage에 이미지 업로드하기

dependencies {
	
	...

	implementation 'com.google.firebase:firebase-storage-ktx'
}

Firebase Storage를 사용하기 위해 build.gradle(Module) 파일에 라이브러리를 추가한다.

class GalleryFragment(uri: Uri): Fragment() {
    private lateinit var mBinding: FragmentGalleryBinding
    private var uri: Uri? = uri

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        mBinding = FragmentGalleryBinding.inflate(inflater, container, false)

        mBinding.postPhotoIV.setImageURI(uri)   //갤러리에서 선택한 이미지를 해당 이미지뷰에서 보여줌.
        //게시글 업로드 버튼을 누르면 Firebase Storage에 이미지를 업로드 하는 함수 실행.
        mBinding.postButton.setOnClickListener {
            uploadImageTOFirebase(uri!!)
        }

        return mBinding.root
    }

    //Firebase Storage에 이미지를 업로드 하는 함수.
    fun uploadImageTOFirebase(uri: Uri) {
        var storage: FirebaseStorage? = FirebaseStorage.getInstance()   //FirebaseStorage 인스턴스 생성
        //파일 이름 생성.
        var fileName = "IMAGE_${SimpleDateFormat("yyyymmdd_HHmmss").format(Date())}_.png"
        //파일 업로드, 다운로드, 삭제, 메타데이터 가져오기 또는 업데이트를 하기 위해 참조를 생성.
        //참조는 클라우드 파일을 가리키는 포인터라고 할 수 있음.
        var imagesRef = storage!!.reference.child("images/").child(fileName)    //기본 참조 위치/images/${fileName}
        //이미지 파일 업로드
        imagesRef.putFile(uri!!).addOnSuccessListener {
            Toast.makeText(activity, getString(R.string.upload_success), Toast.LENGTH_SHORT).show()
        }.addOnFailureListener {
            println(it)
            Toast.makeText(activity, getString(R.string.upload_fail), Toast.LENGTH_SHORT).show()
        }
    }
}
  1. mBinding.postPhotoIV.setImageURI(uri) : 이미지 뷰에 사용자가 선택한 이미지를 넣어준다.
  2. mBinding.postButton.setOnClickListener { uploadImageTOFirebase(uri!!) } : 게시글 업로드 버튼을 누르면 Firebase Storage에 이미지를 업로드한다.
  3. FirebaseStorage 인스턴스를 생성한다.
  4. 파일 이름을 IMAGE_날짜_시간_.png 형식으로 지정한다.
  5. imagesRef로 스토리지에 이미지를 저장할 경로를 지정한다.
  6. putFile() 메서드를 호출해 이미지를 imagesRef 경로에 저장한다.

파이어 베이스 스토리지에 위와 같이 이미지가 저장된 것을 확인할 수 있다.

[출처] Charlezz-액티비티 결과 처리하기 (Good bye… startActivityForResult, onActivityResult)
[출처] 랴파파의 콜렉션-안드로이드 코틀린:Firebase Storage 이미지 저장
[출처] 파이어베이스 스토리지 공식 문서

profile
개발을 즐기고 잘하고 싶은 안드로이드 개발자입니다 :P

0개의 댓글