프로그래밍 언어/Flutter

[Flutter] 웹뷰 안드로이드 이미지 파일 첨부 오류

이로률 2025. 3. 1. 19:24

flutter로 안드로이드 사진 파일 첨부 시 파일 첨부가 안되는 오류가 발생하였다. 
Chrome 모바일 버전과 iOS에서는 파일 첨부가 잘 되고 있지만 안드로이드만 안된다.
또 ,,, 안드로이드 배포는 targetSdkVersion을 34 이상으로 해야한다고 한다.

 

**중요 *
2024년 9월 2일 작성

Adnroid 14 이상부터 사진/동영상 일부 접근 권한 (사진/동영상의 일부 접근 권한) 추가

AndroidManifest.xml

<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
<uses-permission android:name="android.permission.READ_MEDIA_VISUAL_USER_SELECTED" tools:node="remove" />

dart

void imagePicker(String call) async {
  final picker = ImagePicker();
  final XFile? pickedFile = await picker.pickImage(source: ImageSource.gallery);

  if (pickedFile != null) {
    final bytes = await File(pickedFile.path).readAsBytes();
    final base64String = base64Encode(bytes);
    final Map<String, String> result = {
      'base64String': base64String,
      'fileName': pickedFile.name,
      'fileExt': pickedFile.name.split('.').last.toLowerCase()
    };

    send(call: call, data: jsonEncode(result));
  } else {
    alert(title: '오류', msg: '이미지를 선택하세요.');
  }
}

vuejs

<template>
  <div class="py-[1.125rem] relative flex">
    <label for="file01">
       <div class="break-keep text-[#0E66F2] pr-6 text-base reading-file flex items-center" @click="triggerFileInput('file01')">파일 선택</div>
    </label>
    <input type="file" id="file01" hidden accept="image/*" @change="onChangeFile($event, 'file01')">
  </div> 
</template>
<script>
methods: {    
    triggerFileInput(fileType) {
      this.fileType = fileType
      const platform = window.$nativeManager.getPlatform();
      if (platform === 'android') {
        window.$nativeManager.call({
          call: 'imagePicker',
          data: {},
        });
      }
    },
    onImageSelected(imageData) {
      const fileName = imageData.fileName;
      const base64String = imageData.base64String;
      const fileExt = imageData.fileExt;

      const mimeTypes = {
        'png': 'image/png',
        'jpg': 'image/jpeg',
        'jpeg': 'image/jpeg'
      };

      const mimeString = mimeTypes[fileExt] || 'application/octet-stream';

      // Base64 문자열을 디코드하여 ArrayBuffer로 변환
      const byteString = atob(base64String);
      const arrayBuffer = new ArrayBuffer(byteString.length);
      const uintArray = new Uint8Array(arrayBuffer);

      for (let i = 0; i < byteString.length; i++) {
        uintArray[i] = byteString.charCodeAt(i);
      }

      // Blob을 File로 변환
      const file = new File([arrayBuffer], fileName, { type: mimeString });

      const dataTransfer = new DataTransfer();
      dataTransfer.items.add(file);

      const inputElement = document.getElementById(this.fileType);
      inputElement.files = dataTransfer.files;

      const e = { target: { files: dataTransfer.files } };
      this.onChangeFile(e, this.fileType);
    },
    onChangeFile(e, key) {
      const fileList = e.target.files
      const addFileList = []

      for (const element of fileList) {
        const file = element
        const fileSize = file.size
        const fileExt = file.name.substring(file.name.lastIndexOf('.') + 1).toLowerCase()

        if (fileSize > this.fileMaxSize) {
          window.cmimToast('첨부파일의 크기는 최대 10MB로 제한됩니다.')
          console.log('10MB 가 넘어서 파일일 추가 할 수 없음')
          continue
        }

        if (this.fileExts.indexOf(fileExt) === -1) {
          window.cmimToast(`첨부파일은 ${this.fileExts.join(',')}의 확장자만 등록 가능합니다.`)
          console.log(this.fileExts.join(','), '확장자만 가능')
          continue
        }

        addFileList.push(file)
      }

      this[key] = addFileList
      this[key + 'Error'] = false

      e.target.value = null;
    },
}
</script>