본문 바로가기

UIKIT

나중에 꼭 해봐야할 "공유" 기능 -> UIActivityViewController

https://chatgpt.com/c/671889af-9864-800f-bb99-851914559f3b

 

 

 

위에 이미지 처럼 공유할 때 나오게 하고싶습니다. 

그래서 구현을 해봤는데.... 

 

   func shareButtonCalled() {
        detailSpotView.sharedButton.addTarget(self, action: #selector(didTappedSharedButton), for: .touchUpInside)
    }
        

    // MARK: - Actions
    // 공유 버튼을 누르면 호출되는 함수
    @objc func didTappedSharedButton(_ sender: Any) {
        
        guard let contentid = selectedSpotItem?.contentid,
              let contenttypeid = selectedSpotItem?.contenttypeid,
              let title = selectedSpotItem?.title  else { return }
        
        
        let spotURLString = "https://takeTrip.com/spot/\(contenttypeid)/\(contentid)"
        
        if let spotURL = URL(string: spotURLString) {
            var shareObject = [Any]()
            
            let travelTitle = "[테이크트립]: 여긴 어때? \(title))"
            shareObject.append(travelTitle)
            shareObject.append(spotURL)
            
            let activityViewController = UIActivityViewController(activityItems : shareObject, applicationActivities: nil)
            activityViewController.popoverPresentationController?.sourceView = self.view

            //activityViewController.excludedActivityTypes = [UIActivity.ActivityType.airDrop, UIActivity.ActivityType.postToFacebook,UIActivity.ActivityType.postToTwitter,UIActivity.ActivityType.mail]

            self.present(activityViewController, animated: true, completion: nil)
            
        }
    }

 

 

 

 

여기서 문제가 발생하는데... 

일단은 .. 공유된 내용에 이미지랑, 제목이 나오지 않습니다...

 

 


https://developer.apple.com/documentation/uikit/uiactivityviewcontroller

 

UIActivityViewController | Apple Developer Documentation

A view controller that you use to offer standard services from your app.

developer.apple.com

 

개요 (Overview)

UIActivityViewController는 iOS, iPadOS, Mac Catalyst, 그리고 visionOS에서 제공되는 시스템 서비스로, 복사, 소셜 미디어에 게시, 이메일 및 SMS로 항목 전송 등의 표준 기능을 제공합니다. 또한, 앱에서 정의한 커스텀 서비스를 추가할 수도 있습니다.

앱은 이 뷰 컨트롤러를 설정, 표시, 닫는 역할을 담당합니다. 설정은 이 뷰 컨트롤러가 작업할 데이터 객체를 지정하는 과정으로 이루어집니다. (앱이 지원하는 커스텀 서비스도 지정할 수 있습니다.)

이 뷰 컨트롤러를 표시할 때는 적절한 방식으로 해야 합니다.

  • iPad에서는 popover로 표시해야 하고,
  • iPhoneiPod touch에서는 모달(modal) 형식으로 표시해야 합니다.

주제 (Topics)

1. Activity View Controller 초기화 (Initializing the activity view controller):

  • init(activityItems: [Any], applicationActivities: [UIActivity]?)
    • 지정된 데이터에 대해 동작하는 새로운 UIActivityViewController 객체를 초기화합니다.
  • init(activityItemsConfiguration: any UIActivityItemsConfigurationReading)
    • 지정된 구성(configuration)에 대해 동작하는 새로운 UIActivityViewController 객체를 초기화합니다.

2. UIActivityItemsConfiguration 클래스:

  • UIActivityItemsConfiguration
    • 다양한 상호작용을 통해 데이터를 내보낼 수 있는 구성을 제공하는 클래스입니다.

3. UIActivityItemsConfigurationReading 프로토콜:

  • UIActivityItemsConfigurationReading
    • 활동 항목 구성을 담당하는 객체가 이 프로토콜을 구현하여 필요한 데이터를 내보냅니다.

4. 완료 핸들러 접근 (Accessing the completion handler):

  • var completionWithItemsHandler: UIActivityViewController.CompletionWithItemsHandler?
    • UIActivityViewController가 닫힌 후에 실행할 완료 핸들러를 지정합니다.
  • typealias UIActivityViewController.CompletionWithItemsHandler
    • UIActivityViewController가 닫힌 후에 실행할 완료 핸들러를 위한 타입 별칭입니다.

5. 특정 활동 유형 제외 (Excluding specific activity types):

  • var excludedActivityTypes: [UIActivity.ActivityType]?
    • 표시되지 않아야 할 서비스 목록을 지정합니다.

6. 특정 섹션 제외 (Excluding specific sections):

  • var excludedActivitySectionTypes: UIActivitySectionTypes
    • 제외할 섹션 목록을 지정합니다.

7. 주요 활동을 강조 (Elevating a prominent activity):

  • var allowsProminentActivity: Bool
    • 시스템이 특정 활동을 더 눈에 띄게 할 수 있는지 여부를 지정하는 부울 값입니다.

 

 

UIActivityViewController를 사용하여 텍스트, 이미지, 비디오와 같은 데이터를 공유하는 방법을 예시로 들어드리겠습니다. 이 예제들은 텍스트나 파일을 공유할 때 사용자가 선택할 수 있는 시스템 서비스(메시지, 이메일, 소셜 미디어 공유 등)를 제공합니다.

 

1. 텍스트(메모) 공유 예시:

앱에서 간단한 텍스트를 공유할 때, 아래와 같은 코드를 사용하여 UIActivityViewController를 표시할 수 있습니다.

 

@objc func shareText() {
    let textToShare = "여기는 내가 기록한 중요한 메모입니다."  // 공유할 텍스트
    
    // UIActivityViewController 생성
    let activityViewController = UIActivityViewController(activityItems: [textToShare], applicationActivities: nil)
    
    // iPad에서의 popover 위치 지정 (iPhone에서는 필요 없음)
    activityViewController.popoverPresentationController?.sourceView = self.view
    
    // 공유 화면 표시
    self.present(activityViewController, animated: true, completion: nil)
}

 

 

이 코드를 실행하면 **텍스트(메모)**가 공유되고, 사용자는 메시지, 이메일, 복사 등의 옵션을 선택할 수 있습니다.

 

 

 

2. 이미지를 공유할 때도 크게 다르지 않습니다. 

activityItems 라는 파라미터에 공유하려는 🔥 데이터 (텍스트, 이미지, 비디오 등)을 배열 형태로 전달합니다. 

@objc func shareImage() {
    if let image = UIImage(named: "sampleImage") {  // 공유할 이미지 설정
        let activityViewController = UIActivityViewController(activityItems: [image], applicationActivities: nil)
        
        // iPad에서의 popover 위치 지정 (iPhone에서는 필요 없음)
        activityViewController.popoverPresentationController?.sourceView = self.view
        
        // 공유 화면 표시
        self.present(activityViewController, animated: true, completion: nil)
    }
}

 

 

3. 비디오 공유 예시:

이 예제에서는 "sampleVideo.mp4" 파일을 공유하며, 메시지 앱이나 소셜 미디어 앱 등을 통해 비디오를 전송할 수 있습니다.

@objc func shareVideo() {
    if let videoURL = Bundle.main.url(forResource: "sampleVideo", withExtension: "mp4") {  // 공유할 비디오 URL 설정
        let activityViewController = UIActivityViewController(activityItems: [videoURL], applicationActivities: nil)
        
        // iPad에서의 popover 위치 지정 (iPhone에서는 필요 없음)
        activityViewController.popoverPresentationController?.sourceView = self.view
        
        // 공유 화면 표시
        self.present(activityViewController, animated: true, completion: nil)
    }
}

 

 

4. 비디오, 이미지, 텍스트 함께 공유 예시:

@objc func shareTextImageAndVideo() {
    let textToShare = "여기는 내가 기록한 중요한 메모입니다."
    if let imageToShare = UIImage(named: "sampleImage"),
       let videoURL = Bundle.main.url(forResource: "sampleVideo", withExtension: "mp4") {
        let activityViewController = UIActivityViewController(activityItems: [textToShare, imageToShare, videoURL], applicationActivities: nil)
        
        // iPad에서의 popover 위치 지정 (iPhone에서는 필요 없음)
        activityViewController.popoverPresentationController?.sourceView = self.view
        
        // 공유 화면 표시
        self.present(activityViewController, animated: true, completion: nil)
    }
}

 

 

추가 설정: 특정 공유 타입 제외하기

특정 활동 타입(예: AirDrop)을 제외하고 싶을 때는 **excludedActivityTypes**를 사용합니다. 예를 들어, AirDropFacebook을 제외한 공유 방법만 표시하고 싶다면:

 

이 코드는 AirDrop과 Facebook을 제외한 공유 서비스만 표시하도록 합니다.

@objc func shareWithExclusions() {
    let textToShare = "이 메모는 특정 앱으로만 공유할 수 있습니다."
    
    let activityViewController = UIActivityViewController(activityItems: [textToShare], applicationActivities: nil)
    
    // AirDrop과 Facebook 제외
    activityViewController.excludedActivityTypes = [.airDrop, .postToFacebook]
    
    // iPad에서의 popover 위치 지정 (iPhone에서는 필요 없음)
    activityViewController.popoverPresentationController?.sourceView = self.view
    
    // 공유 화면 표시
    self.present(activityViewController, animated: true, completion: nil)
}

 

🔥 applicationActivities 란?

 

applicationActivities는 **UIActivityViewController**의 생성자에서 사용되는 매개변수로, 앱에서 제공하는 커스텀 서비스활동을 정의할 수 있는 옵션입니다. 기본적으로 UIActivityViewController는 시스템에서 제공하는 표준 서비스(예: 메시지, 이메일, 복사, 소셜 미디어 공유 등)를 자동으로 표시하지만, applicationActivities를 통해 **앱 자체에서 제공하는 맞춤형 기능(활동)**을 추가할 수 있습니다.

applicationActivities의 역할:

  • 기본 시스템 활동 외에 앱에서 정의한 맞춤형 활동을 추가할 수 있습니다.
  • 예를 들어, 시스템에서 제공하지 않는 특정 기능(예: 내부적으로 데이터를 저장하는 기능이나 사용자 지정 공유 옵션)을 추가하고 싶을 때 UIActivity를 상속한 커스텀 클래스를 만들어 이를 applicationActivities에 전달할 수 있습니다.

 

UIActivity 클래스:

applicationActivities에 추가할 활동은 UIActivity 클래스를 상속하여 정의합니다. 이를 통해 새로운 사용자 정의 기능을 UIActivityViewController의 목록에 포함시킬 수 있습니다.

간단한 예시: 커스텀 활동 추가

예를 들어, 앱에서 "내부 메모에 저장"이라는 활동을 추가하고 싶다면, 다음과 같이 사용자 정의 활동을 만들 수 있습니다.

1. 커스텀 활동 정의 (UIActivity 서브클래스)

class SaveToNotesActivity: UIActivity {
    override var activityTitle: String? {
        return "Save to Notes"
    }
    
    override var activityImage: UIImage? {
        return UIImage(systemName: "note.text")  // 커스텀 아이콘
    }
    
    override var activityType: UIActivity.ActivityType? {
        return UIActivity.ActivityType("com.example.app.saveToNotes")  // 고유한 활동 타입
    }
    
    override func canPerform(withActivityItems activityItems: [Any]) -> Bool {
        // 이 활동을 지원할지 여부를 결정 (예: 텍스트만 지원)
        return activityItems.contains { $0 is String }
    }
    
    override func perform() {
        // 활동을 수행할 코드 (예: 텍스트를 메모에 저장하는 로직)
        print("Saving to notes...")
        activityDidFinish(true)  // 작업 완료 알림
    }
}

 

 

이 코드는 **"Save to Notes"**라는 커스텀 활동을 정의하고, 텍스트가 주어진 경우에만 작동하게 합니다.

2. UIActivityViewController에 커스텀 활동 추가

@objc func shareWithCustomActivity() {
    let textToShare = "이 텍스트를 메모에 저장합니다."
    
    // 커스텀 활동 생성
    let saveToNotesActivity = SaveToNotesActivity()
    
    // UIActivityViewController에 커스텀 활동 추가
    let activityViewController = UIActivityViewController(activityItems: [textToShare], applicationActivities: [saveToNotesActivity])
    
    // iPad에서의 popover 위치 지정 (iPhone에서는 필요 없음)
    activityViewController.popoverPresentationController?.sourceView = self.view
    
    // 공유 화면 표시
    self.present(activityViewController, animated: true, completion: nil)
}

 

위 코드에서 **saveToNotesActivity**는 커스텀 활동으로, 사용자가 선택할 수 있는 옵션에 **"Save to Notes"**가 추가됩니다.

요약:

applicationActivities는 UIActivityViewController에 시스템에서 제공하는 표준 활동 이외의 커스텀 활동을 추가할 수 있는 기능입니다. 이를 통해 앱에서만 제공되는 고유한 서비스(예: 메모 저장, 사용자 정의 공유 기능 등)를 사용자에게 제공할 수 있습니다.

 

 

 

위의 이미지처럼 앱 이름, 그리고 제목을 공유하는 기능을 구현하려면 UIActivityViewController와 **LPLinkMetadata**를 사용하여 미리보기 정보(이미지, 제목, 앱 이름 등)를 설정할 수 있습니다. 아래는 이를 구현하는 방법입니다.

1. UIActivityViewController와 LPLinkMetadata 개념

UIActivityViewController는 기본적으로 공유할 텍스트, 이미지, URL 등을 제공하는 역할을 하며, **LPLinkMetadata**는 **미리보기(Preview)**에서 보여줄 메타데이터를 설정하는 역할을 합니다.

  • 이미지: 공유할 여행지의 대표 이미지
  • 앱 이름: 고정된 문자열 (예: "데이트립")
  • 제목: 여행지의 간단한 소개 텍스트

2. 구현 계획

  • UIActivityViewController를 사용하여 공유할 항목을 설정
  • 이미지, 제목, 앱 이름을 메타데이터로 추가하여 미리보기에 표시되도록 구성

3. 구현 예시

다음 코드는 여행지 정보를 이미지, 제목, 앱 이름과 함께 공유하도록 설정하는 방법입니다.

 

1. ShareItemSource 클래스 수정 (이미지와 텍스트 포함)

import LinkPresentation
import SDWebImage

class ShareItemSource: NSObject, UIActivityItemSource {
    var title: String
    var url: URL
    var imageURL: URL?
    var messageText: String
    
    init(title: String, url: URL, imageURL: URL?, messageText: String) {
        self.title = title
        self.url = url
        self.imageURL = imageURL
        self.messageText = messageText
    }
    
    // 기본적으로 반환할 아이템 (메시지 텍스트)
    func activityViewControllerPlaceholderItem(_ activityViewController: UIActivityViewController) -> Any {
        return messageText
    }
    
    // 활동 타입에 따라 텍스트나 이미지를 반환
    func activityViewController(_ activityViewController: UIActivityViewController, itemForActivityType activityType: UIActivity.ActivityType?) -> Any? {
        return messageText // 메시지 텍스트 공유
    }
    
    // 앱 아이콘과 이미지를 메타데이터로 설정
    func activityViewControllerLinkMetadata(_ activityViewController: UIActivityViewController) -> LPLinkMetadata? {
        let metadata = LPLinkMetadata()
        metadata.title = title // 여행지 제목
        metadata.originalURL = url // 여행지 URL
        
        // 앱 이름 설정
        metadata.iconProvider = NSItemProvider(object: UIImage(named: "appIcon")!) // 앱 아이콘 (여기서는 "appIcon" 이미지 사용)
        
        // 이미지 URL이 있으면 SDWebImage로 이미지를 다운로드
        if let imageURL = imageURL {
            SDWebImageDownloader.shared.downloadImage(with: imageURL) { (image, data, error, finished) in
                if let image = image, finished {
                    metadata.imageProvider = NSItemProvider(object: image) // 여행지 이미지 설정
                }
            }
        }
        
        return metadata
    }
}

 

 

2. UIActivityViewController 설정 (미리보기 포함)

@objc func shareSpotDetails() {
    guard let contentid = selectedSpotItem?.contentid,
          let contenttypeid = selectedSpotItem?.contenttypeid,
          let title = selectedSpotItem?.title,
          let imageURLString = selectedSpotItem?.imageURL,
          let spotURL = URL(string: "https://daytrip.com/spot/\(contenttypeid)/\(contentid)") else { return }
    
    // 메시지 텍스트 구성
    let appName = "[데이트립]"
    let messageText = "\(appName) \(title)\n\(spotURL.absoluteString)"
    
    // 이미지 URL을 https로 변환
    let securePosterURLString = imageURLString.replacingOccurrences(of: "http://", with: "https://")
    
    if let imageURL = URL(string: securePosterURLString) {
        // ShareItemSource 생성
        let itemSource = ShareItemSource(title: title, url: spotURL, imageURL: imageURL, messageText: messageText)
        
        // UIActivityViewController 생성
        let activityViewController = UIActivityViewController(activityItems: [itemSource], applicationActivities: nil)
        
        // iPad에서는 popover 위치 지정
        activityViewController.popoverPresentationController?.sourceView = self.view
        
        // 공유 화면 표시
        self.present(activityViewController, animated: true, completion: nil)
    }
}

 

 

4. 주요 포인트

  • **LPLinkMetadata**에서 이미지, 제목, URL, 앱 아이콘을 설정하여 공유 화면의 미리보기를 구성할 수 있습니다.
  • 이미지는 SDWebImageDownloader를 사용해 비동기적으로 다운로드한 후, 미리보기에 설정됩니다.
  • 앱 이름은 고정된 텍스트로 설정되어 있으며, 이를 messageText에 포함시켜 공유할 수 있습니다.

요약:

위의 코드를 사용하면 여행지 정보를 공유할 때 이미지, 앱 이름, 제목이 함께 포함된 미리보기가 표시됩니다. 이를 통해 사용자는 여행지 정보를 쉽게 확인하고, 소셜 미디어, 메시지, 이메일 등을 통해 공유할 수 있습니다.