Share Extension

김재형·2024년 9월 10일
1
post-custom-banner

시작하기 앞서

혹시 공유하기 기능을 알고 계신가요?
당연히 알고 계시겠죠 히히

그렇다면 공유하기 할 때 앱 마다 작은 앱이 나오는 원리라는것을 알고 계셨나요?
저도 이번 출시앱을 개발하다 보니 알게 되서 공유해보고자 합니다.
이번 시간에는 Share Extension 에 대해서 배워 보도록 하겠습니다!

Share Extension

사용자가 앱과 콘텐츠를 공유할 수 있도록 하는 확장(Extension)앱 입니다.
이를 통해 사용자는 다른 앱에서 텍스트, 이미지, URL 등 다양한 형태의 데이터를 가져와서
자신의 앱으로 공유할 수 있습니다.

간단 사용법

위 사진과 같이 Share Extention 를 추가하시고

App Group 을 생성하시고 활성화 해주세요
주의 하실 부분은 main App 의 App Group 도 활성화 해주셔야 합니다!

NSExtensionActivationSupportsWebURLWithMaxCount = 확장에서 지원할 최대 URL 수를 지정
위와 같이 ShareExtention infoplist 를 활성화 해주세요

import Social
import Combine
import UniformTypeIdentifiers

final class ShareViewController: UIViewController {
    
    private var viewModel = SharedViewModel()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        setting()
        handleSharedURL()
    }
    
    private func setting() {
        ... UI 구성 관련
    }
    
    private func setLayout(viewCon: UIViewController) {
        ... Layout 관련 
    }
    
    private func handleSharedURL() {
        // 공유된 항목 가져오기
        if let item = extensionContext?.inputItems.first as? NSExtensionItem {
            if let attachments = item.attachments {
                for provider in attachments {
                    // URL을 처리하기 위한 타입 확인
                    if provider.hasItemConformingToTypeIdentifier(UTType.url.identifier) {
                        provider.loadItem(forTypeIdentifier: UTType.url.identifier, options: nil) { (item, error) in
                            if let url = item as? URL {
                                // YouTube URL 확인 및 처리
                                self.processYouTubeURL(url)
                            }
                        }
                    } else if provider.hasItemConformingToTypeIdentifier(UTType.text.identifier) {
                        provider.loadItem(forTypeIdentifier: UTType.text.identifier, options: nil) { (item, error) in
                            if let url = item as? String {
                                // YouTube URL 확인 및 처리
                                self.processYouTubeURL(url)
                            }
                        }
                    }
                }
            }
        }
    }
    
    private func processYouTubeURL(_ url: URL) {
        // 앱 그룹을 통해 메인 앱에 전달
        if let userDefaults = UserDefaults(suiteName: "group.guideu.youtube"),
           let encode = encoding(string: url.absoluteString) {
            
            userDefaults.setValue(encode, forKey: "sharedURL")
            print("공유받은 YouTube URL: \(url.absoluteString)")

            userDefaults.synchronize()
            
            DispatchQueue.main.async { [weak self] in
                self?.viewModel.trigger = true
            }
        } else {
            close()
        }
    }
    
    private func processYouTubeURL(_ string: String) {
        
        // 앱 그룹을 통해 메인 앱에 전달
        if let userDefaults = UserDefaults(suiteName: "group.guideu.youtube"),
           let encode = encoding(string: string) {
            
            userDefaults.setValue(encode, forKey: "sharedURL")
            print("공유받은 YouTube URL: \(string)")

            userDefaults.synchronize()
            
            DispatchQueue.main.async { [weak self] in
                self?.viewModel.trigger = true
            }
        } else {
            close()
        }
    }
    
    private func encoding(string: String) -> Data? {
        return try? JSONEncoder().encode(string)
    }
    
    private func close() {
        // Share Extension 종료 및 앱 이동
        self.extensionContext?.completeRequest(returningItems: [], completionHandler: nil)
    }
    
    private func openMainApp() {
        let urlScheme = "guideu://"
        if let url = URL(string: urlScheme) {
            // 앱 실행
            if self.openURL(url) {
                print( "RUN : APP")
            } else {
                print( "NOT RUN : APP")
            }
            close()
        }
    }
    
    @objc private func openURL(_ url: URL) -> Bool {
        var responder: UIResponder? = self
        while responder != nil {
            if let application = responder as? UIApplication {
                return application.perform(#selector(openURL(_:)), with: url) != nil
            }
            responder = responder?.next
        }
        return false
    }
}

final class SharedViewModel: ObservableObject {
    @Published var trigger = false
}

위와 같이 간단하게 구성해 보았는데요!
약간 생소하신 코드가 하나가 보일것입니다.

@objc private func openURL(_ url: URL) -> Bool {
        var responder: UIResponder? = self
        while responder != nil {
            if let application = responder as? UIApplication {
                return application.perform(#selector(openURL(_:)), with: url) != nil
            }
            responder = responder?.next
        }
        return false
    }

약간 의문이 들었을수도 있다고 생각이 듭니다.
다만, Share Extention 에선 UIApplication.shared.open(<#T##url: URL##URL#>)
를 사용할 수가 없습니다

위와 같은 방법을 통해서도 open URL을 실행 시킬수 있습니다!

완성후 UI

출시후 공개 예정

profile
IOS 개발자 새싹이
post-custom-banner

0개의 댓글