Cordova -> Capacitor로 현재 프로젝트를 migration하면서 내가 이전에 개발했던 기능은 capacitor의 camera 플러그인으로 교체하게 되었다. 그런데 안드로이드로 빌드해 확인해보니 파일 시스템의 다른 이미지(화면 캡처본, 다운로드 파일)는 정상적으로 이미지를 가져와 화면에 출력하는데 직접 핸드폰 디바이스로 촬영한 사진을 선택했을 때만 Unable to process image 오류가 발생했다. 사진을 직접 찍는 방식으로 바꿔 테스트해보니 또 바로 찍은 이미지는 정상적으로 가져온다.
서치한 결과 안드로이드 개발자 분이 네이티브 코드를 뜯어보고 오류의 발생 원인을 찾고 감사하게도 설명을 남겨주신 것을 찾았다. Capacitor가 v2 -> v3으로 가면서 화면 회전 방향에 따른 이미지 자동 회전 기능에서 오류가 생긴 것. 해당 기능 옵션은 correctOrientation인데 default 값이 true이어서 따로 지정하지 않으면 자동으로 적용된다. 이미지 회전을 하는 내부 코드의 imageUrl.getPath() 메서드 호출이 오류가 된다. sdk 버전에 따라 content uri를 imageUrl.getPath()이 아닌 ContentProvider로 access해야 하기 때문이라고.
Capacitor 얼른 이 오류 고쳐줘요 ~~
출처: https://github.com/ionic-team/capacitor/issues/2060
회사에서 Windows를 쓰기 때문에 안드로이드 기준으로 개발하고 나서 맥북으로 iOS 에서 이상 없는지 빌드하여 확인하는 편인데, Cordova도 Capacitor도 역시 iOS는 호락호락하지 않다. 안드로이드의 경우 getPhoto()로 가져온 파일의 url을 string으로 받아 직접 img src에 넣어줘도 무방하나, iOS는 절대 출력되지 않는다. Cordova의 경우는 ionic-webview, Capacitor의 경우 Capacitor를 import해서 file url 형태로 컨버팅을 해주어야 한다. 그런 다음 컨버팅한 url을 SafeResourceUrl로 다시 한 번 변환해주어야 무사히 출력할 수 있다는 사실.
Capacitor의 경우 convertFileSrc()를 거치지 않고 SafeResourceUrl로 바로 변환했을 때 화면 출력까지는 문제가 없었으나 dom-to-image를 사용하는 등 HTMLElement를 처리하게 될 경우 이미지가 날라가는 재밌는 현상을 볼 수 있다. 그러니 꼭 dom element를 읽어 사용할 일이 없다고 하더라도 file src로 컨버팅하는 과정을 생략하지 않는 것이 좋겠다.
import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser'; // DomSanitizer 의존성 주입 필요
import { Camera, CameraResultType, CameraSource } from '@capacitor/camera';
import { Capacitor } from '@capacitor/core';
imageUrl: SafeResourceUrl;
Camera.getPhoto({
source: CameraSource.Photos,
allowEditing: false,
correctOrientation: false, // Capacitor V3 -> Android device로 촬영한 image file path 오류 방지
resultType: CameraResultType.Uri
})
.then((photo) => { // iOS image file path 오류 방지 (dom-to-image 정상 동작)
const fileUrl = Capacitor.convertFileSrc(photo.webPath);
const url = this.domSanitizer.bypassSecurityTrustResourceUrl(fileUrl);
this.imageUrl = url;
})
.catch((e) => {
// error reporting
// default image file setting
});