I'm trying to load a remote image into a MTLTexture
with this code:
let textureLoader = MTKTextureLoader(device: device)
textureLoader.newTexture(withContentsOf: url, options: options) { [weak self] (texture, error) in
if let t = texture {
completion(t)
} else {
if let desc = error?.localizedDescription {
NSLog(desc)
}
completion(nil)
}
}
If the URL comes from a Bundle resource, then it works, e.g.
let url = Bundle.main.url(forResource: name, withExtension: ext)
However, it fails if I pass something like this:
let url = URL(string: "http://example.com/images/bla_bla.jpg")
With this error:
Could not find resource bla_bla.jpg at specified location.
If I copy-paste the URL into the browser, the image is displayed without problems (plus I've implemented the same thing in Android using OpenGL and the image renders OK).
I've added my domain to the Info.plist
, and I can load things like JSON from that location. It's just the texture loader being funny. Info.plist
looks like this:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<false/>
<key>NSExceptionDomains</key>
<dict>
<key>example.com</key>
<dict>
<key>NSIncludesSubdomains</key>
<true/>
<key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
<true/>
<key>NSTemporaryExceptionMinimumTLSVersion</key>
<string>TLSv1.1</string>
</dict>
</dict>
</dict>
The MTKTextureLoader
documentation does not mention anything about external URLs, but could it be that it only handles internal resources?
Here's an example of how to extend MTKTextureLoader
to load remote URLs, which are not supported by the default implementation.
extension MTKTextureLoader {
enum RemoteTextureLoaderError: Error {
case noCachesDirectory
case downloadFailed(URLResponse?)
}
func newTexture(withContentsOfRemote url: URL, options: [String : NSObject]? = nil, completionHandler: @escaping MTKTextureLoaderCallback) {
let downloadTask = URLSession.shared.downloadTask(with: URLRequest(url: url)) { (maybeFileURL, maybeResponse, maybeError) in
var anError: Error? = maybeError
if let tempURL = maybeFileURL, let response = maybeResponse {
if let cachePath = NSSearchPathForDirectoriesInDomains(.cachesDirectory, .userDomainMask, true).first {
let cachesURL = URL(fileURLWithPath: cachePath, isDirectory: true)
let cachedFileURL = cachesURL.appendingPathComponent(response.suggestedFilename ?? NSUUID().uuidString)
try? FileManager.default.moveItem(at: tempURL, to: cachedFileURL)
return self.newTexture(withContentsOf: cachedFileURL, options: options, completionHandler: completionHandler)
} else {
anError = RemoteTextureLoaderError.noCachesDirectory
}
} else {
anError = RemoteTextureLoaderError.downloadFailed(maybeResponse)
}
completionHandler(nil, anError)
}
downloadTask.resume()
}
}
Ideally, you would implement your own caching mechanism to avoid repeatedly downloading the same image, but this should get you started.