如何使用 LinkPresentation 在 SwiftUI 中获取链接元数据?

Posted

技术标签:

【中文标题】如何使用 LinkPresentation 在 SwiftUI 中获取链接元数据?【英文标题】:How to fetch Link metadata in SwiftUI using LinkPresentation? 【发布时间】:2021-03-01 18:42:22 【问题描述】:

根据 WWDC20 和其他文章,从给定的 url 获取图像 url 似乎很容易。下面是我的入门代码。这只是列出了一个随机的 url 列表,并且应该为 url 的丰富链接预览获取 imageurl。 一个简单的使用 LPMetadataProvider 获取元数据。但我无法让它显示图像网址。有人知道它在 SwiftUI 中是如何完成的吗?

import SwiftUI
import LinkPresentation

struct ExampleHTTPLinks: View 
    var links = [ "https://www.google.com", "https://www.hotmail.com"]
    let metadataProvider = LPMetadataProvider()
    
    
    var body: some View 
        
        
        List(links, id:\.self)  item in
            HStack 
                Text(item)
                Image(systemName: "heart.fill")
                metadataProvider.startFetchingMetadata(for: URL(string: item)!)  metadata, error in
                  if error != nil 
                    // The fetch failed; handle the error.
                    // Examples: server doesn't respond, is too slow, user doesn't have network.
                    return
                  
                 let linkView = LPLinkView(metadata: metadata)
                    Image(linkView.image)
                  // Make use of the fetched metadata.
                
            
        
    


struct ExampleHTTPLinks_Previews: PreviewProvider 
    static var previews: some View 
        ExampleHTTPLinks()
    

【问题讨论】:

【参考方案1】:

这是一个工作版本:


class LinkViewModel : ObservableObject 
    let metadataProvider = LPMetadataProvider()
    
    @Published var metadata: LPLinkMetadata?
    @Published var image: UIImage?
    
    init(link : String) 
        guard let url = URL(string: link) else 
            return
        
        metadataProvider.startFetchingMetadata(for: url)  (metadata, error) in
            guard error == nil else 
                assertionFailure("Error")
                return
            
            DispatchQueue.main.async 
                self.metadata = metadata
            
            guard let imageProvider = metadata?.imageProvider else  return 
            imageProvider.loadObject(ofClass: UIImage.self)  (image, error) in
                guard error == nil else 
                    // handle error
                    return
                
                if let image = image as? UIImage 
                    // do something with image
                    DispatchQueue.main.async 
                        self.image = image
                    
                 else 
                    print("no image available")
                
            
        
    


struct MetadataView : View 
    @StateObject var vm : LinkViewModel
    
    var body: some View 
        VStack 
            if let metadata = vm.metadata 
                Text(metadata.title ?? "")
            
            if let uiImage = vm.image 
                Image(uiImage: uiImage)
                    .resizable()
                    .frame(width: 100, height: 100)
            
        
    


struct ContentView: View 
    var links = [ "https://www.google.com", "https://www.hotmail.com"]
    let metadataProvider = LPMetadataProvider()
    
    var body: some View 
        List(links, id:\.self)  item in
            HStack 
                Text(item)
                Image(systemName: "heart.fill")
                MetadataView(vm: LinkViewModel(link: item))
            
        
    

如果您尝试将其用于多次调用,LPMetadataProvider 会报错,因此我已将其移至视图模型。

图片是由NSImageProvider 提供的——您可以看到loadObject 调用是从其中获取UIImage 的原因。

请注意,如果您想使用 Apple 提供的开箱即用演示文稿,您可以使用 LPLinkView。因为它是一个UIView,要在 SwiftUI 中使用它,你必须用 UIViewRepresentable 包装它:

struct LPLinkViewRepresented: UIViewRepresentable 
    var metadata: LPLinkMetadata
    
    func makeUIView(context: Context) -> LPLinkView 
        return LPLinkView(metadata: metadata)
    
    
    func updateUIView(_ uiView: LPLinkView, context: Context) 
        
    


struct MetadataView : View 
    @StateObject var vm : LinkViewModel
    
    var body: some View 
        if let metadata = vm.metadata 
            LPLinkViewRepresented(metadata: metadata)
         else 
            EmptyView()
        
    


class LinkViewModel : ObservableObject 
    let metadataProvider = LPMetadataProvider()
    
    @Published var metadata: LPLinkMetadata?
    
    init(link : String) 
        guard let url = URL(string: link) else 
            return
        
        metadataProvider.startFetchingMetadata(for: url)  (metadata, error) in
            guard error == nil else 
                assertionFailure("Error")
                return
            
            DispatchQueue.main.async 
                self.metadata = metadata
            
        
    

【讨论】:

太棒了。这是一件值得学习的好事情——我也需要在我的一个项目中实现它。 你知道如何打印imageurl吗?文本(metadata.imageurl ??“”)不起作用。 我查看了 LPLinkMetadataLPLinkViewNSItemProvider 等的文档,并没有看到任何明显的实际获取 URL 的内容。我的感觉是,如果您特别需要,您可能必须自己执行 http 请求并解析出图像 url。否则,NSItemProvider 会在幕后进行工作以获取图像,而无需让您访问该信息。 好吧,我想是的。但这可能有帮助吗? metaData.imageProvider = NSItemProvider(contentsOf: URL(fileURLWithPath: path ?? "")) 如本文所述? betterprogramming.pub/linkpresentation-in-ios-13-bbb6007818c6 不,这有点倒退。如果你想修改你自己的链接图片。

以上是关于如何使用 LinkPresentation 在 SwiftUI 中获取链接元数据?的主要内容,如果未能解决你的问题,请参考以下文章

Xcode 13 dyld:库未加载:/System/Library/Frameworks/LinkPresentation.framework/LinkPresentation

在添加 LinkPresentation 视图的堆栈上重用单元格时不显示元素

LPLinkView backgroundColor 在 iOS 中不起作用

在 s-s-rS 中使用 STUFF 之前如何排序

如何在 s-s-rS 中使用表达式转移到报告

如何在 s-s-rs 上使用高亮索引参数