[Clone] 인스타그램 클론 프로젝트(4) - 사진 업로드

minnie·2022년 3월 8일
0

클론프로젝트

목록 보기
5/8
post-thumbnail

이번 강의에서는 Firebase에 사진을 업로드하는 페이지를 생성하고 Firebase의 Storage에 업로드 되었는지 확인하였다.

1. Firebase Storage 사용 설정


Firebase에서 Storage로 들어가 시작하기를 누르면 다음과 같은 화면이 나온다. 프로덕션 모드에서 시작으로 체크하고 다음으로 넘어간다.

위치 설정은 기본으로 설정되어있는 것으로 하고 진행하였다.

생성하고 나면 아직 파일이 없습니다라는 문구와 함께 업로드 되어있는 파일이 없는 것을 확인할 수 있다.


2. Android에서 Cloud Storage로 파일 업로드

build.gradle(Module:app)의 dependencies 부분에 다음 라이브러리를 추가해주어 사진을 업로드할 수 있는 스토리지를 추가해준다.

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

사진을 업로드할 Activity와 layout을 만든다. (AddPhotoActivity.kt, activity_add_photo.xml)

먼저 FirebaseStorage 타입의 변수 storage와 이미지 uri를 담을 수 있는 변수 photoUri를 생성한다. photoPickIntent에 Intent(Intent.ACTION_PICK)을 이용해 선택한 이미지를 가져올 수 있도록 한다.
런처를 이용하여 액티비티가 성공했을 때(=사진을 선택햇을 때)선택한 이미지 경로가 전달된다.
photoUri에 전달받은 이미지 경로를 넣어주고 선택된 이미지를 addphoto_image에 표시해준다. 실패했을 때는 액티비티를 종료하도록 finish()를 넣어준다.

var storage: FirebaseStorage? = null
var photoUri: Uri? = null

private lateinit var getResult: ActivityResultLauncher<Intent>

getResult = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
				result: ActivityResult ->
                	if (result.resultCode == RESULT_OK) {
                    	//이미지 경로 넘어옴
                    	photoUri = result.data?.data
                    	binding.addphotoImage.setImageURI(photoUri)
                	}else{
                    	//취소버튼
                    	finish()
                	}
            	}
            
            
storage = FirebaseStorage.getInstance()
val photoPickIntent = Intent(Intent.ACTION_PICK)
photoPickIntent.type = "image/*"
getResult.launch(photoPickIntent)
    

이미지 이름이 중복되지 않도록 파일명에 날짜값을 넣어 지정한다. storageRef에 첫번째 child에는 폴더명을 넣어주고 두번째 child에는 이미지 파일명을 넣어준다.
putFile에 이미지 파일 Uri를 넣어 사진을 업로드 한다. addOnSuccessListener는 업로드 성공할 때 실행되는 리스너이므로 성공했다는 것을 알려주기 위해 토스트 팝업을 넣는다. 이 코드를 업로드 버튼을 눌렀을 때 실행되게 한다.

val timestamp = SimpleDateFormat("yyyyMMdd_HHmmss").format(Date())
val imageFileName = "IMAGE_"+ timestamp + "_.png"

val storageRef = storage?.reference?.child("images")?.child(imageFileName)

//파일 업로드
storageRef?.putFile(photoUri!!)?.addOnSuccessListener {
	Toast.makeText(this,getString(R.string.upload_success),Toast.LENGTH_LONG).show()
}

3. 사진 경로 가져올 수 있는 권한

MainActivity의 onCreate부분에서 아래 코드를 추가해 사진 경로를 가져올 수 있는 권한을 요청하고 onNavigationItemSelected의 해당 item에서 외부 스토리지 경로를 가져올 수 있는 권한이 있는지 체크해주고 권한이 있다면 위에서 생성한 업로드 하는 Activity로 이동시켜준다.

ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE),1)

override fun onNavigationItemSelected(item: MenuItem): Boolean {
	when (item.itemId) {
    	R.id.action_add_photo -> { 	
        	if(ContextCompat.checkSelfPermission(this,Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED){
             	startActivity(Intent(this,AddPhotoActivity::class.java)) 
            }
            return true
   	}
}

그리고 AndroidManifest에서 다음과 같은 권한을 설정해준다.

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

실행시켜보면 맨 처음에 앱에 권한을 허용하는 허용하지 않는지 물어본다. 사진 및 미디어를 사용하기 위해 Allow해준다.

➕ 에뮬레이터에 사진을 넣어주기 위해 아래 링크를 참고하여 이미지를 넣어주었다.
https://planactor.tistory.com/324

하단의 네비게이션바에서 가운데 있는 갤러리로 들어가보면 다음과 같이 사진을 선택할 수 있는 창이 뜬다.

원하는 사진을 선택해주고 업로드를 누르면 사진이 업로드가 된다.

❌ 하지만 업로드버튼을 눌러도 사진이 업로드 되지않고 다음과 같은 오류가 발생하였다.

W/NetworkRequest: No App Check token for request.
E/StorageException: StorageException has occurred.
    User does not have permission to access this object.
     Code: -13021 HttpResult: 403
E/StorageException: The server has terminated the upload session

원인을 찾아보니 Storage의 Rules를 수정해주어야한다. 기본 설정은 allow read, write: if false; 라고 되어있을 것이다. 이 부분에서 false를 true로 변경시켜주면 모든 사용자에게 권한을 주는 것이고 request.auth != null; 이렇게 변경시켜주면 로그인 한 사용자에게 권한을 주는 것이다.


이제 Firebase의 Storage에 들어가보면 다음과 같이 폴더가 생기고 이미지 파일이 업로드 되어있을 것 이다.

참고
https://firebase.google.com/docs/storage/android/upload-files?hl=ko

profile
Android Developer

0개의 댓글