Search code examples
iosswiftbundleon-demand-resources

How Does Apple's On Demand Resource System download files to the App's Main Bundle?


I am currently trying to implement Apple's API for On Demand Resource Management for AWS Cloudfront because Apple's ODR is somehow too unreliable.

I noticed that when I tag images inside of Assets.scnassets/ with an ODR resource tag, I can access that image using

UIImage(name: resourceName)

once it has been downloaded by a NSBundleRequest object. Because I can access the downloaded resource as a UIImage, I know that the resource is located in the app's main bundle but I thought this was impossible because Bundles were read-only. How did apple do this? The most important aspect is being able to create UIImages using this incredibly simple interface.


Solution

  • Not sure how it is done technically, but I am pretty certain that attributing ODR to a particular bundle (typically main) is done on purpose, so you can rely on it.

    I am using RxOnDemandResources library to fetch hundreds of MP3 from dozens of tags, and it is done on a per bundle basis -

    Bundle
        .main
        .rx
        .demandResources(withTags: tags) // tags: Set<String>
        .subscribeOn(Scheduler.concurrentUser) // declare your scheduler first
        .observeOn(Scheduler.concurrentMain) // declare your scheduler first
        .subscribe { event in
            switch event {
            case .next(let progress):
                self.showProgress(progress: Float(progress.fractionCompleted)) // declare your handler first
            case .error(let error):
                break // handle appropriately
            case .completed:
                if let url = Bundle.main.url(forResource: file, withExtension: "") {
                    os_log("url: %@", log: Log.odr, type: .info, "\(url)")
                    // TODO use your resource
                }
            }
        }
        .disposed(by: self.disposeBag)

    Back to your question: yes you can access ODR resources via specific bundle as usual but with all preconditions (checking availability, fetching if needed) - i.e. not always.