rive-app / rive-ios

iOS runtime for Rive
MIT License
484 stars 55 forks source link

Need to handle corrupt .riv files from the web or from local resources #224

Open imougy opened 2 years ago

imougy commented 2 years ago

Currently, if the .riv file is missing from the resources or if the file https link doesn't exist, the app will crash. We need to handle this situation. The recommended way is to display something to indicate that fact instead of the current crash. Here is an example that shouldn't crash, where fileNotHere.riv is not in the local resources, or https://linkIsNotValid.riv is not a valid link.

struct ContentView: View {

    var body: some View {
        HStack{
//            RiveViewModel(fileName: "fileNotHere").view() 
            RiveViewModel(webURL: "https://linkIsNotValid.riv").view()
        }
    }
}
mjtalbot commented 1 year ago

I'm not 100% sure what the best practice is here for an iOS library, and we are certainly open to opinions from the community on how to handle this.

So far we've tried to simply "bubble" errors up, so library users can handle them how they see fit. For us that means we try not to catch errors, as we don't want to hide the underlying issue (like networking issues).

neon8bit commented 5 months ago

Hi there!

Having the same problem :) Sorry if I just missed something, but how from the app side I could handle this crash? I attach our code below as an example. I would be happy to use a try-catch here, but it's not possible as there are no throwable functions from Rive in this case. So, Rive basically just crashes the app, and doesn't let us catch an exception and handle it in our code.

guard let riveFile = RiveFile(httpUrl: "https://invalidUrl.riv", loadCdn: true, with: delegate) else {
    return
}
let riveModel = RiveModel(riveFile: riveFile)
self.riveViewModel = RiveViewModel(riveModel) // crash happens here
self.riveViewModel?.setView(self.riveMediaView)

I see that there is this method in RiveFileDelegate:

/*
 * Delegate to inform when a rive file is loaded
 */
@protocol RiveFileDelegate <NSObject>
- (BOOL)riveFileDidLoad:(RiveFile*)riveFile error:(NSError**)error;
@end

And when implementing this protocol method in Swift, it looks like this (also with as example implementation):

func riveFileDidLoad(_ riveFile: RiveFile) throws {
    if riveFile.isLoaded {
        let riveModel = RiveModel(riveFile: riveFile)
        let riveViewModel = RiveViewModel(riveModel) // crash happens here
        self.didLoad(riveViewModel)
    } else {
        self.didFail() // could also throw an Error here, but doesn't matter, in our case we don't end up on this line of code
    }
}

So, on our side we can throw an error, but we still unable to catch any errors from Rive itself, it just crashes.

Could you help us a bit with this please? Maybe, I just don't see something here :)