0

I'm trying to get deep linking working for my app's widgets. The widgets simply display an image from a Core Data entity: Project. I'd like for when a user taps on the widget, it opens up the ProjectDetailView() that the image is a member of. Everything I read says I should be able to add Link(destination: url) but I'm not getting anywhere with that. In my app, project is pulled from Core Data, but it has no url attribute. I feel like it doesn't need one based on the examples I've seen?

The below code gives me the error Value of type 'FetchedResults<Project>' has no member 'url' which is true.. it doesn't. I don't understand how to get the url to the ProjectDetailView() the image is included in. Thanks so much for taking a look!

struct SimpleEntry: TimelineEntry {
    let date: Date
    
}

struct WidgetEntryView : View {
    
    var entry: Provider.Entry
    @State var projectImage1: Data = .init(count: 0)
    @FetchRequest(entity: Project.entity(), sortDescriptors: []) var project: FetchedResults<Project>
    
    var body: some View {
        
        if let randomProject: Project = project.randomElement() {
            Link (destination: project.url) {
            Image(uiImage: UIImage(data: randomProject.image1 ?? self.projectImage1) ?? UIImage(imageLiteralResourceName: "icon"))
                .resizable()
                .aspectRatio(contentMode: .fill)
            }
        }
    }
}
phiredrop
  • 182
  • 1
  • 11
  • You should walk through the [Widget Code Along](https://developer.apple.com/videos/play/wwdc2020/10034/) it will walk you through everything there are 3 parts and there is sample code where you can see everything that is called. – lorem ipsum Apr 10 '21 at 00:19
  • Thanks for the reply, however I have looked at this. Their app is setup very different. `url` is defined in their CharacterDetail.swift. I don't have properties defined for my `Project` because it's a Core Data entity. – phiredrop Apr 14 '21 at 17:50

1 Answers1

0

If you look at the url in their CharacterDetail.swift it is something like "game:///spouty" game to represent the app the :/// to conform to url and something unique.

So all you need to get a url for for your file is to follow the same pattern.

yourApp:///anyUniqueVariable

You can achieve this in an extension of your object class with a computed variable.

extension Project{
    var url: URL{
       return URL(string: "yourApp:///\(self.anyUniqueVariable)")
    }
}

You keep saying you have a CoreData object that isn't really relevant because the actual connection is made in with SwiftUI and how you "trigger" your NavigationLink to the View that displays your object.

If you look at the ContentView.swift you'll see

        .onOpenURL(perform: { (url) in
            self.pandaActive = url == CharacterDetail.panda.url
            self.spoutyActive = url == CharacterDetail.spouty.url
            self.eggheadActive = url == CharacterDetail.egghead.url
        })

They are using the NavigationLink init with isActive and triggering the making it true when the "received url == the characters url".

You could use that method (might not be the best since you likely have more than 3 objects) or the init with NavigationLink that has selection and set the tag/selection variable to the url you received in openURL.

It just depends on how you want to trigger your NavigationLink.

lorem ipsum
  • 21,175
  • 5
  • 24
  • 48
  • Thank for the added details. It seems like I'd want to create the url extension something like `URL(string: "myApp:///\(self.objectID)")` since the image being displayed is part of the objectID of the entire Project - and the ProjectDetails() view is what I'd want opened when tapping the widget. However wrapping this optional with `!` fails saying unexpectedly found nil while unwrapping, so I question if I'm on thinking about this right. – phiredrop Apr 16 '21 at 16:40
  • `objectID` might have "forbidden" characters. Look at this [SO question](https://stackoverflow.com/questions/1547899/which-characters-make-a-url-invalid) so see what makes it invalid and this [SO question](https://stackoverflow.com/questions/43291242/how-can-we-remove-every-characters-other-than-numbers-dot-and-colon-in-swift) details how to trim a `String` – lorem ipsum Apr 16 '21 at 17:27
  • 1
    I had some time to look this up and `URL(string: "app:///\(items.first!.objectID.uriRepresentation().absoluteString)")!` works. Just plain `objectId` does not qualify as something that can go in a `URL` – lorem ipsum Apr 19 '21 at 12:11
  • Thank for the info. Still struggling to get this working though - the app just opens like normal. Feels like there's still a missing piece. – phiredrop Apr 27 '21 at 15:40
  • The stuff inside the onOpenURL. You have to set the selected item – lorem ipsum Apr 27 '21 at 16:54