iOS

✏️ Link Presentation으로 메타데이터 가져오기

_yunie 2024. 5. 29. 11:45

오늘은 Link Presentation을 이용해 메타데이터를 가져오는 방법에 대해 글을 써보고자 합니다.
생각보다 해당 프레임워크를 사용하는 방법의 글이 많지 않아 애를 먹었던 과거의 저처럼 또 필요하실 분들이 있을지도 모르니까요!

Link Presentation ?

그럼 우선 Link Presentation이 무엇을 하는 프레임워크인지부터 알아봅시다.
Link Presentation을 사용하면 URL 내의 메타데이터를 찾아 해당 데이터들을 LPLinkMetadata 형태로 가지고 와 화면에 표시해 줄 수 있습니다.
이때에 사용되는 것이 LPLinkView로 링크의 제목과 아이콘, 관련 이미지, 오디오, 비디오 등을 기반으로 링크를 제공해 줍니다. (이미지 참고)

 


하지만 그렇다고 꼭 LPLinkView를 이용하여 메타데이터를 표시해줘야 하는 것은 아닙니다.
제가 사용했던 방법처럼 우선 메타데이터를 가져와 원하는 TextField 또는 Label과 같이 다양한 곳에도 메타데이터를 표시해 줄 수 있습니다.



ErrorCase 정의

가장 먼저 할 일은 메타데이터를 가져올 때, 메타데이터 내 이미지를 가져올 때 등 경우를 나누어 각각의 에러를 정의하는 것입니다.
만약 메타데이터를 가져오지 못했을 때와 성공적으로 가져왔을 때를 구분하지 않는다면 원래라면 채워져야 할 Label이 비어있거나 하는 경우가 생길 수 있겠죠?
그리고 메타데이터를 가져오는데 실패했을 때 사용자에게 명시적으로 이를 알려주면 어째서 해당 Label이 메타데이터를 가져온다고 했는데도 비어있는지 이해할 수 있게 됩니다.

저는 메타데이터에서 제목과 URL, 아이콘(썸네일)이 필요했기 때문에 제가 참고했던 게시글처럼 메타데이터를 불러오지 못했을 때, 아이콘을 불러오지 못했을 때, 아이콘이 없을 때 이렇게 총 세 가지 경우를 에러 사항으로 정의해 주었습니다.

// 데이터 불러올 때, 아이콘 불러올 때 에러 정의
enum LPLoaderCase: Error {
    // 메타데이터를 불러오지 못했을 때
    case metadataLoadingFailed
    // 아이콘을 불러오지 못했을 때
    case faviconCouldNotBeLoaded
    // 아이콘이 없을 때
    case faviconDataInvalid
}



LPMetadataProvider

다음으로 간단하게 메타데이터를 가져오는 방법을 알아보겠습니다.
Apple Developer Documentation에 따르면 링크 내 메타데이터(LPLinkMetadata)는 LPMetadataProvider내 startFetchingMetadata를 이용해 가져올 수 있습니다.
startFetchingMetadata 메서드는 아래와 같은 형태로 URL을 입력값으로 주었을 때, 해당 링크의 메타데이터를 반환합니다.

open func startFetchingMetadata(for URL: URL) async throws -> LPLinkMetadata

 

그리고 이를 이용해 에러(메타데이터를 불러오지 못한 경우)와 성공적으로 가져왔을 때를 코드로 작성한다면 아래와 같이 작성할 수 있습니다.
do-catch 구문을 통해 우선 링크의 메타데이터를 불러오도록 해보고 에러가 발생한다면 catch 구문에서 해당 에러를 받아옵니다.
만약 메타데이터가 성공적으로 불러와졌다면 metadata를 반환합니다.

// URL 통해 메타데이터 불러오기
func load(for url: URL) async throws -> LPLinkMetadata {
	// metadataProvider : URL에서 메타데이터를 검색하는 객체
	let metadataProvider = LPMetadataProvider()
    // 현재 URL의 메타데이터를 가진 객체
    let metadata: LPLinkMetadata
    // 메타데이터 불러오기
    do {
    	metadata = try await metadataProvider.startFetchingMetadata(for: url)
    } catch { // 데이터를 불러오는데 실패했다면
        throw LPLoaderCase.metadataLoadingFailed
    }
    return metadata
}

 

메타데이터 불러오기 생각보다 어렵지 않죠?
단순하게 메타데이터 내 제목이나 URL을 가져오고 싶다면 이렇게만 해주면 됩니다!



NSItemProvider Extension

문제는 메타데이터 내 아이콘을 가지고 오고 싶을 때입니다.
위의 코드에서도 확인했다시피 메타데이터를 가져오는 metadataProvider는 async/await를 통해 비동기적으로 데이터를 불러올 수 있습니다. 하지만 아이콘을 불러오는 iconProvider는 NSItemProvider 타입으로 async/await을 제공하지 않습니다. 그래서 데이터를 보다 효율적으로 사용하는 비동기 작업을 위해서는 NSItemProvider을 확장하여 async/await을 준수하도록 만들어주어야 합니다.

여기서 loadDataRepresentation의 매개변수의 타입인 _UTType_을 짧게 설명하자면 파일 형식 및 데이터 유형을 식별하기 위한 표준을 의미합니다. 다양한 곳에서 파일 형식을 식별하고 처리해야 하는 데 사용되는 일종의 규범으로 파일 형식을 관리하고 다루는 데 있어 유용한 표준이라고 볼 수 있습니다. 자세하게는 다음에 다뤄볼게요😉

 

import LinkPresentation
import UniformTypeIdentifiers

// loadDataRepresentation을 async/await 할 수 있도록 수정
extension NSItemProvider {
    func loadDataRepresentation(for type: UTType) async throws -> Data {
        return try await withCheckedThrowingContinuation { continuation in
            _ = self.loadDataRepresentation(for: type) { data, error in
                if let data {
                    // 불러온 데이터 return
                    continuation.resume(returning: data)
                } else if let error {
                    // 에러 던지기
                    continuation.resume(throwing: error)
                }
            }
        }
    }
}



메타데이터 내 아이콘, 이미지 가져오기

자, 이제 다 왔습니다!
우리는 메타데이터 내 아이콘 또는 이미지를 가져올 준비가 끝났어요!
메타데이터 내 아이콘은 LPMetadata에서 iconProvider를 통해 가져올 수 있습니다.

아래의 코드가 작동하는 과정을 보면 다음과 같습니다.

  • metadata 변수가 가진 아이콘을 iconProvider을 이용해 가져온다
  • 실패했다면 error를 던진다
  • 성공했다면 Data 형태로 가져온 아이콘을 UIImage로 변환하여 반환한다
    // iconProvider : URL에서 썸네일을 검색하는 객체
     guard let iconProvider = metadata.iconProvider else {
              throw LPLoaderCase.faviconCouldNotBeLoaded // 아이콘을 불러올 수 없다면
          }
          // 아이콘(썸네일) 데이터 정의
          let iconData: Data
          do {
              iconData = try await iconProvider.loadDataRepresentation(for: .image) // 아이콘(썸네일) 불러오기
          } catch {
              throw LPLoaderCase.faviconCouldNotBeLoaded // 메타(아이콘)데이터를 불러올 수 없을때
          }
          // 불러온 아이콘(썸네일)을 UIImage로 변환
          guard let icon = UIImage(data: iconData) else {
              throw LPLoaderCase.faviconDataInvalid // 아이콘이 없는 경우
          }
          return icon // 아이콘(썸네일) 반환
      }

메타데이터를 불러오는 과정과 크게 다를 게 없어서 해볼 만합니다☺️
눈여겨볼 점이라면 loadDataRepresentation(for: )이 부분입니다.
현재는 아이콘 이미지를 받아오고 있어 image를 주었지만 다른 형태의 데이터를 받아올 때에는 UTType 포함되는 video, audio, avi 등 다양한 형식으로도 받아올 수 있는 것 같습니다 :)

만약 아이콘이 아니라 이미지를 불러오고 싶다면 iconProvider 부분을 imageProvider로만 변경해 주시면 됩니다!



실사용

제가 실제로 메타데이터를 여러 플랫폼에서 불러와 본 결과, 어떤 곳은 iconProvider로 불러올 수 있었고 어떤 곳은 imageProvider로만 불러올 수 있는 곳이 있었습니다.

그래서 저는 썸네일이 비는 경우가 되도록 없게 하기 위해 처음엔 imageProvider를 이용해 이미지를 받아올 수 있도록 했습니다.
그리고 만약 imageProvider로 불러올 이미지가 없을 때, error를 알리는 알림 대신 iconProvider를 이용해 아이콘을 불러오도록 했습니다.
그래도 error가 발생한다면 불러올 썸네일이 없거나 정말 불러올 수 없는 경우이므로 각 상황에 맞게 알림창을 띄우도록 해주었습니다.

// 메타데이터 불러오기
do {
    let metadata = try await LPLoader().load(for: url)
    self.titleTextField.text = metadata.title

// 아이콘 불러오기
// 1차적으로 imageProvider 이용해서 썸네일 가져오기
// -> 없다면(에러발생 시) iconProvider이용해서 아이콘 가져오기
// -> 아이콘도 없다면 썸네일 불러올 수 없다는 팝업 띄우기
    do {
         let thumbnail = try await LPLoader().thumbnail(metadata: metadata)
          self.thumbnailImageView.image = thumbnail
    } catch {
          switch error {
        default:
        do {
            let icon = try await LPLoader().favicon(metadata: metadata)
               self.thumbnailImageView.image = icon
           } catch {
             switch error {
                 case LPLoaderCase.faviconCouldNotBeLoaded:
                    ms.alert(for: "썸네일을 불러올 수 없어요")
                 case LPLoaderCase.faviconDataInvalid:
                    ms.alert(for: "불러올 썸네일이 없어요")
                default:
                    ms.alert(for: "썸네일을 불러올 수 없어요")
                }
            }
          }
         }
  } catch {
    switch error {
        case LPLoaderCase.metadataLoadingFailed: ms.alert(for: "데이터를 불러오는데 실패했어요")
      default: break
  }
}



🗣️ 후기

이렇게 오늘은 Link Presentation을 이용해 메타데이터를 불러오고 이를 통해 또 아이콘과 썸네일을 받아오는 방법을 알아보았습니다! 고작 이거 가지고 뭘 그렇게 헤맸냐고 하시는 분들도 있을 수 있지만 저는 정말 저 글 하나 없었다면 꽤 막막했을 것 같아 영어보다는 한국어로 좀 더 편하게 보시라고 한 번 작성해 봤습니다☺️ 아직 배워가는 단계인만큼 부족함이 많기에 만약 보완할 점이 있다면 알려주세요🙏



📚 참고

https://alexanderweiss.dev/blog/2023-04-16-lpmetadataprovider-extract-url-metadata
https://developer.apple.com/documentation/linkpresentation