[Android / Kotlin] Firebase Storage 이미지 파일 업로드/다운로드/삭제

Subeen·2023년 3월 13일
0

Android

목록 보기
10/73
post-thumbnail

📍 결과 동영상

  • 원형 이미지 뷰를 클릭하면 앨범을 호출한다.
  • 선택 된 이미지의 uri를 전달 받아 ImageView에 표시한다.
  • 등록하기 버튼을 클릭하면 Storage에 파일을 업로드한다.
  • Storage 파일 업로드가 성공일 경우 Toast 메시지를 띄워준다.

📍 Firebase Storage 만들기

Firebase Console 화면에서 빌드 탭 아래 Storage 메뉴를 클릭한다.
Storage 메뉴에서 시작하기를 클릭한다.

시작하기를 클릭하면 Cloude Storage 설정 팝업이 나타난다. 첫 번째로 보안 규칙을 설정한다.

설정 팝업에서 두 번째로 위치를 설정한다.

설정이 완료되면 보안 규칙(Rules) 탭에서 read, write 설정을 다음과 같이 true로 수정해준다.

📍 앱에 Firebase 인증 추가

모듈(앱 수준) Gradle 파일에서 storage 라이브러리의 종속 항목을 추가한다.

dependencies {
    implementation platform('com.google.firebase:firebase-bom:31.2.2')

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

📍 Cloude Storage 설정

이미지를 업로드/다운로드 하기 위해 파일을 가리키는 Cloude Storage 참조를 생성한다.

// storage 인스턴스 생성
val storage = Firebase.storage
// storage 참조
val storageRef = storage.getReference("image")
// 파일 경로와 이름으로 참조 변수 생성
val fileName = SimpleDateFormat("yyyyMMddHHmmss").format(Date())
val mountainsRef = storageRef.child("${fileName}.png")

📍 Storage 함수 정리

📌 파일 업로드

파일을 업로드 하는 함수로 저장되는 파일의 이름이 중복되는 것을 방지하고자 파일명에 날짜를 넣어 저장한다.
파일을 가리키는 참조를 생성한 후 putFile에 이미지 파일 uri를 넣어 파일을 업로드한다.

    private fun imageUpload(uri: Uri) {
        // storage 인스턴스 생성
        val storage = Firebase.storage
        // storage 참조
        val storageRef = storage.getReference("image")
        // storage에 저장할 파일명 선언
        val fileName = SimpleDateFormat("yyyyMMddHHmmss").format(Date())
        val mountainsRef = storageRef.child("${fileName}.png")

        val uploadTask = mountainsRef.putFile(uri)
        uploadTask.addOnSuccessListener { taskSnapshot ->
            // 파일 업로드 성공
            Toast.makeText(getActivity(), "사진 업로드 성공", Toast.LENGTH_SHORT).show();
        }.addOnFailureListener {
            // 파일 업로드 실패
            Toast.makeText(getActivity(), "사진 업로드 실패", Toast.LENGTH_SHORT).show();
        }
    }

📌 URL을 통해 파일 다운로드

URL을 통해 파일을 다운로드 하는 함수로 성공했을 경우 파일의 url을 가져온다.

    private fun imageDownload() {
        // storage 인스턴스 생성
        val storage = Firebase.storage
        // storage 참조
        val storageRef = storage.getReference("image")
        // storage에서 가져올 파일명 선언
        val fileName = SimpleDateFormat("yyyyMMddHHmmss").format(Date())
        val mountainsRef = storageRef.child("${fileName}.png")

        val downloadTask = mountainsRef.downloadUrl
        downloadTask.addOnSuccessListener { uri ->
            // 파일 다운로드 성공
            // Glide를 사용하여 이미지를 ImageView에 직접 가져오기
            Glide.with(mainActivity).load(uri).into(binding.imageArea)
        }.addOnFailureListener {
            // 파일 다운로드 실패
        }
    }

📌 파일 삭제

파일을 삭제하는 함수로 파일을 가리키는 참조를 생성한 후 delete() 메서드를 호출한다.

    private fun imageDelete() {
        // storage 인스턴스 생성
        val storage = Firebase.storage
        // storage 참조
        val storageRef = storage.getReference("image")
        // storage에서 삭제 할 파일명
        val fileName = SimpleDateFormat("yyyyMMddHHmmss").format(Date())
        val mountainsRef = storageRef.child("${fileName}.png")

        val deleteTask = mountainsRef.delete()
        deleteTask.addOnCompleteListener {
            // 파일 삭제 성공
        }.addOnFailureListener {
            // 파일 삭제 실패
        }
    }

📍 Code

👩🏻‍💻 파일 업로드 화면 Layout 구성하기

먼저 앱 수준 Gradle 파일에서 원형 이미지뷰를 구현하기 위해 'de.hdodenhof:circleimageview:3.1.0'를 추가하고,
이미지를 다운로드 받아서 이미지뷰에 표시하기 위해 'com.github.bumptech.glide:glide:4.12.0'를 추가해준다.

dependencies {
    implementation 'com.github.bumptech.glide:glide:4.12.0'
    
    implementation 'de.hdodenhof:circleimageview:3.1.0'
}
  • fragment_user.xml
    이미지뷰를 원형으로 표시하기 위해 <de.hdodenhof.circleimageview.CircleImageView/>를 사용한다.
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".fragment.UserFragment">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">

            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:gravity="center"
                android:text="프로필 이미지"
                android:textColor="@color/black"
                android:textSize="20sp"
                android:textStyle="bold" />

            <de.hdodenhof.circleimageview.CircleImageView
                android:id="@+id/imageArea"
                android:layout_width="150dp"
                android:layout_height="150dp"
                android:layout_gravity="center"
                android:layout_margin="20dp"
                android:src="@drawable/profile" />

            <Button
                android:id="@+id/btnRegister"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_margin="20dp"
                android:background="@color/black"
                android:text="업로드하기"
                android:textColor="@color/white"
                android:textSize="18sp" />
        </LinearLayout>

    </FrameLayout>
</layout>

👩🏻‍💻 파일 업로드 화면 Activity 구현하기

📌 registerForActivityResult

  • Activity에서 결과를 받아올 때 startActivityForResult() 와 onActivityResult()를 사용 했지만
    deprecated 되었기에 registerForActivityResult를 사용한다.
  • registerForActivityResult는 initialization, onAttach(), onCreate() 에서
    registerForActivityResult()를 호출 해야 한다.
  • 사용 방법
    • registerForActivityResult를 사용해서 결과 콜백을 등록한다.
      결과를 받기 위해서 액티비티를 실행하는 StartActivityForResult()를 인자 값으로 넣어준다.
      result 객체가 파라미터로 전달되고 result 객체를 통해 원하는 데이터를 얻을 수 있다.
    • launch()를 통해 데이터를 받아올 액티비티를 실행한다.
  • UserFragment.kt
class UserFragment : Fragment() {
    private lateinit var binding: FragmentUserBinding
    private lateinit var uri: Uri
    lateinit var mainActivity: MainActivity

    override fun onAttach(context: Context) {
        super.onAttach(context)

        mainActivity = context as MainActivity
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
    }

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        binding = DataBindingUtil.inflate(inflater, R.layout.fragment_user, container, false)

		// 이미지뷰를 눌렀을 경우 
        binding.imageArea.setOnClickListener {
        	// ACTION_PICK을 사용하여 앨범을 호출한다.
            val intent = Intent(Intent.ACTION_PICK, MediaStore.Images.Media.INTERNAL_CONTENT_URI)
            registerForActivityResult.launch(intent)
        }

		// 등록하기 버튼을 눌렀을 경우 
        binding.btnRegister.setOnClickListener {
            imageUpload(uri)
        }

        return binding.root
    }

    private val registerForActivityResult =
        registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
            when (result.resultCode) {
                AppCompatActivity.RESULT_OK -> {
                    // 변수 uri에 전달 받은 이미지 uri를 넣어준다.
                    uri = result.data?.data!!
                    // 이미지를 ImageView에 표시한다.
                    binding.imageArea.setImageURI(uri)
                }
            }
        }

    private fun imageUpload(uri: Uri) {
        // storage 인스턴스 생성
        val storage = Firebase.storage
        // storage 참조
        val storageRef = storage.getReference("image")
        // storage에 저장할 파일명 선언
        val fileName = SimpleDateFormat("yyyyMMddHHmmss").format(Date())
        val mountainsRef = storageRef.child("${fileName}.png")

        val uploadTask = mountainsRef.putFile(uri)
        uploadTask.addOnSuccessListener { taskSnapshot ->
            // 파일 업로드 성공
            Toast.makeText(getActivity(), "사진 업로드 성공", Toast.LENGTH_SHORT).show();
        }.addOnFailureListener {
            // 파일 업로드 실패
            Toast.makeText(getActivity(), "사진 업로드 실패", Toast.LENGTH_SHORT).show();
        }
    }

}

👀 Firebase Storage 저장 된 데이터 확인하기

profile
개발 공부 기록 🌱

0개의 댓글