[swift] PromiseKit를 이용한 앱 내 스크린샷 및 스크롤 캡처 구현 방법

앱 개발 시 종종 스크린샷이나 스크롤 캡처 기능이 필요한 경우가 있습니다. 이번 블로그 포스트에서는 Swift에서 PromiseKit를 이용하여 앱 내 스크린샷 및 스크롤 캡처를 구현하는 방법을 알아보겠습니다.

1. PromiseKit 설치 및 Import

먼저, PromiseKit를 프로젝트에 추가해야 합니다. Cocoapods를 사용하는 경우 Podfile에 다음과 같이 추가합니다.

pod 'PromiseKit', '~> 6.0'

프로젝트 디렉토리에서 pod install 명령어를 실행하여 PromiseKit를 다운로드하고 설치합니다.

PromiseKit를 사용하기 위해 해당 모듈을 import 합니다.

import PromiseKit

2. 스크린샷 캡처 구현

스크린샷 캡처 기능은 UIApplication.shared.keyWindow를 사용하여 현재 앱의 키 윈도우를 검색합니다. 그런 다음 해당 키 윈도우를 기반으로 스크린샷을 생성합니다.

아래의 코드는 Promise를 사용하여 스크린샷을 캡처하는 예제입니다.

func captureScreenshot() -> Promise<UIImage> {
    return Promise { seal in
        DispatchQueue.main.async {
            guard let keyWindow = UIApplication.shared.keyWindow else {
                seal.reject(PMKError.invalidCallingConvention)
                return
            }
            
            UIGraphicsBeginImageContextWithOptions(keyWindow.bounds.size, false, 0.0)
            keyWindow.drawHierarchy(in: keyWindow.bounds, afterScreenUpdates: false)
            guard let image = UIGraphicsGetImageFromCurrentImageContext() else {
                UIGraphicsEndImageContext()
                seal.reject(PMKError.invalidCallingConvention)
                return
            }
            
            UIGraphicsEndImageContext()
            seal.fulfill(image)
        }
    }
}

위의 코드에서는 Promise를 생성하여 스크린샷을 캡처하는 작업을 비동기적으로 수행합니다. DispatchQueue.main.async를 사용하여 메인 스레드에서 해당 작업이 실행되도록 합니다. 캡처된 이미지는 UIImage 형식으로 Promise가 성공적으로 완료될 때 반환됩니다.

3. 스크롤 캡처 구현

스크롤 캡처 기능은 스크롤 뷰의 콘텐츠 전체를 캡처하는 것을 의미합니다. 이 기능을 구현하기 위해서는 스크롤 뷰의 contentSize를 기준으로 여러 장의 이미지로 스크롤을 이동하며 캡처해야 합니다.

아래의 코드는 Promise를 사용하여 스크롤 캡처를 구현하는 예제입니다.

func captureScrollingScreenshot(scrollView: UIScrollView) -> Promise<UIImage> {
    return Promise { seal in
        DispatchQueue.main.async {
            let savedContentOffset = scrollView.contentOffset
            let savedFrame = scrollView.frame
            
            let contentSize = scrollView.contentSize
            let numberOfScreenshots = Int(ceil(contentSize.height / savedFrame.size.height))
            
            UIGraphicsBeginImageContextWithOptions(contentSize, true, 0.0)
            
            scrollView.contentOffset = .zero
            
            for index in 0 ..< numberOfScreenshots {
                let savedBounds = scrollView.bounds
                
                let originY = savedFrame.size.height * CGFloat(index)
                let rectToCapture = CGRect(x: 0, y: originY, width: savedBounds.size.width, height: savedBounds.size.height)
                
                scrollView.bounds = rectToCapture
                scrollView.drawHierarchy(in: rectToCapture, afterScreenUpdates: true)
                
                if let capturedImage = UIGraphicsGetImageFromCurrentImageContext() {
                    capturedImage.draw(at: CGPoint(x: 0, y: savedBounds.size.height * CGFloat(index)))
                }
                
                scrollView.bounds = savedBounds
            }
            
            let screenshotImage = UIGraphicsGetImageFromCurrentImageContext()
            
            UIGraphicsEndImageContext()
            
            scrollView.contentOffset = savedContentOffset
            
            if let image = screenshotImage {
                seal.fulfill(image)
            } else {
                seal.reject(PMKError.invalidCallingConvention)
            }
        }
    }
}

위의 코드에서는 UIScrollViewcontentSize를 기준으로 스크롤 캡처를 수행합니다. scrollView.bounds를 조정하여 스크롤 위치를 이동하고, scrollView.drawHierarchy(in: rectToCapture, afterScreenUpdates: true)로 해당 위치의 스크린샷을 생성합니다. 마지막으로, 캡처된 여러 이미지를 하나의 이미지로 병합하여 최종 결과를 반환합니다.

결론

PromiseKit를 사용하여 앱 내에서 스크린샷 및 스크롤 캡처 기능을 구현하는 방법에 대해 알아보았습니다. 이러한 기능을 활용하면 앱에 다양한 스크린샷 관련 기능을 추가할 수 있습니다. PromiseKit를 사용하면 비동기 작업을 더 효율적으로 처리할 수 있으며, 코드의 가독성과 유지 보수성을 향상시킬 수 있습니다.