Creating default metal library from ios framework - swift

I am creating a framework which includes several metal files, while creating default library using device?.makeDefaultLibrary()
(when this framework is embedded in a project), application is crashing. It turns out that without specifying Bundle() to makeDefaultLibrary() it only searches for library in main bundle, but as per requirement compiler should search for library in embedded framework's bundle (a .metallib file is being generated while creating Framework).
I have tried specifying bundle as below:
A.
let frameworkBundle = Bundle(for: type(of: self))
let bundleLib = try device?.makeDefaultLibrary(bundle: frameworkBundle)
B.
let frameworkBundle = Bundle(identifier: "com.myframework")
let bundleLib = try device?.makeDefaultLibrary(bundle: frameworkBundle)
Still the application is crashing, I have also noticed that in both the above methods frameworkBundle is returned as nil.

Offering this as an answer, and more than happy to delete it if it doesn't help.
I have a library of CIKernels that are text files with a .cikernel suffix. These are contained in a framework and I created a function to open them as needed by specifying the bundle name like this:
let myBundle = Bundle.init(identifier: "com.mycompany.myframework")
let kernelPath = (myBundle?.path(forResource: "cikernels", ofType: "bundle"))! + "/" + named + ".cikernel"
In your case, I think you need "com.myframework".
Basically, from what I see in your question and the documentation, it looks like a Bundle is an NSObject (about the most basic object you can have and you (properly done) code is allowing a nil return if you are passing in the correct bundle.
See if this works for you. Good luck!
EDIT:
A second thought - my creation of a Bundle uses Bundle.init(identifier:). Maybe that's all you need instead of my "overkill" method? :-)

You can try this:
let frameworkBundle = Bundle(for: type(of: self))
let metalLibraryPath = frameworkBundle.path(forResource: "default", ofType: "metallib")!
let bundleLib = device?.makeLibrary(filepath:metalLibraryPath)

Related

Use Images in a swift framework

I need a picture to appeare in a framework. The only way i found needed that i know the name of the app it is in. Is there another way to get assets into your framework?
(For getting this posted:
my background search didnt help)
Almost 5 years ago I posted this answer. It contains two pieces of code to pull out an asset from a Framework's bundle. The key piece of code is this:
public func returnFile(_ resource:String, _ fileName:String, _ fileType:String) -> String {
let identifier = "com.companyname.appname" // replace with framework bundle identifier
let fileBundle = Bundle.init(identifier: identifier)
let filePath = (fileBundle?.path(forResource: resource, ofType: "bundle"))! + "/" + fileName + "." + fileType
do {
return try String(contentsOfFile: filePath)
}
catch let error as NSError {
return error.description
}
So what if your framework, which needs to know two things (app bundle and light/dark mode) tweaked this code? Move identifier out to be accessible to the app and not local to this function. Then create either a new variable (I think this is the best way) or a new function to work with the correct set of assets based on light or dark mode.
Now your apps can import your framework, and set things up in it's consumers appropriately. (I haven't tried this, but in theory I think it should work.)

Mac Sandbox issues with opening embedded RTF files

My Mac programs usually ship with some internal Rich Text files containing legal details. I use the NSWorkspace openFile call to open the files within TextEdit.
The code looks something like this:
guard let aPath = Bundle.main.path(forResource: “Legal.rtf”, ofType: nil) else { return }
NSWorkspace.shared.openFile(aPath, withApplication: nil)
This has always worked, until recently when this code returns “The application can’t be opened. -50”. Is that a Sandbox issue? Accessing files within your bundle should be allowed. We do it for images and such.
What do I have set wrong?
Thank you!
Thank you for your comments.
I should have mentioned at first that parameter string I had included both filename and the file type (extension). So I would have to split them, something that was easy to do with NSString, but is not immediately available for Swift String. A bit of conversion would have given me the two strings.
However, that OpenFile has been replaced with the newer open(_:)
let name = "Legal.rtf"
guard let aURL = Bundle.main.url(forResource: name, withExtension: "") else { return }
NSWorkspace.shared.open(aURL)
This call does NOT mind if you pass it string with both parts.

SpriteKit in screensaver can't find images

I am making a screensaver in Swift using SpriteKit.
While testing screensaver in app, all the textures load properly. As soon as I make .saver and load it in System Preferences, SpriteKit shows that images are not found.
I used (imageNamed: ""), so I tried using
var imageURL = Bundle.main.url(forResource: "gradient", withExtension: "png")
let imageGradient = NSImage(contentsOf: imageURL!)!
,but I got the same result.
SpriteKit can't access images when built into .saver file, but works perfectly when ran through the app.
I have included images in bundle, in assets, in Target's Copy Bundle Resources/Development Assets/Resource Tags.
You can clone the project from here: https://github.com/Nazar-Bibik/SavePortal
I have looked into this project: https://github.com/leebradley/nyan-screensaver
And I found how to properly do it:
You need to put images into bundle, not xcassets ( put it with .swift files )
Instead of using image name use the following
let sourceBundle = Bundle(for: MainSwiftFile.self)
let imagePath = sourceBundle.path(forResource: "picture-name", ofType: "png")!
neededTextures = SKTexture(imageNamed: imagePath)
You need to provide the name of the .swift file with your principal class ( principle class in info.plist file ).
The rest is simple - forResource is a file name, ofType is a file extension and instead of passing usual name in imageNamed: you provide String of path to file.
"imagePath" is of a String type.

Swift: How to unzip file not contained in my bundle?

I am not very familiar with Swift programming but I need to write a small tool in Swift which can unzip a file (and then launch a program). I need to unzip a file which is not contained in my app bundle. It is located in /Users/me/folder1/folder2/openjdk-11.0.2.zip
I tried the libraries "Zip", "ZipFoundation", and "SSZipArchive". From what I read so far, I think that the libraries which I tried need the zip file to be located in the app bundle but I am not sure.
With "Zip" I tried:
_ = try Zip.quickUnzipFile(URL(string: openjdkZipUrl!.relativePath)!)
With "ZipFoundation" I tried:
let fileManager = FileManager()
let archive = openjdkZipUrl
let destinationURL = openjdkFolderUrl
do {
try fileManager.unzipItem(at: archive.url, to: destinationURL)
} catch {
}
ZipFoundation told me "Value of type 'FileManager' has no member 'unzipItem'" but I imported it with import Foundation. I also have it (and the other libraries) in my Podfile.
With "SSZipArchive" I tried:
let success = SSZipArchive.unzipFile(atPath: openjdkZipUrl!.path, toDestination: openjdkFolderUrl!.path)
The used paths are
let openjdkZip = "file:///Users/" + user + "/folder1/folder2/openjdk-11.0.2.zip"
let openjdkZipUrl = URL(string: openjdkZip)
and
let openjdkFolder = "file:///Users/" + user + "/folder1/folder2/openjdk-11.0.2"
let openjdkFolderUrl = URL(string: openjdkFolder)
Is it really a problem that the zip file is not contained in my bundle? Can someone tell me what I did wrong?
Thanks in advance
#trojanfoe mentioned in the comments:
Mac apps are sandboxed by default which means they have no access to a user's files unless they ask for it by getting the user to open the file/folder. You should ensure it's turned off for your app, however you are testing if the file exists and if this is succeeding then it looks like sandboxing is not turned on?
I looked at the .entitlements file in my project and found out that "App Sandbox" was set to "YES". I set it to "NO" and it worked perfectly.
It seems that you can check for a file while in sandbox mode (as I did with my condition) but not access them when trying to unzip them.
Thanks again #trojanfoe :)

NSBundle.mainBundle().URLForResource("bach1", withExtension: "jpg") returning null

NSBundle.mainBundle().URLForResource("bach1", withExtension: "jpg")
The above code is returning null.
In order to check if the file exists or not, I used below code:
let fileManager = NSFileManager.defaultManager()
if fileManager.fileExistsAtPath(savepath) {
println("exist")
}
The above code returns that file exists in directory.
So I don't understand why the first code is returning null
Your problem is that NSBundle.mainBundle().URLForResource("bach1", withExtension: "jpg") returns an optional NSURL. You need to use if let to unwrap it and extract your file path from the returned url as follow:
if let resourceUrl = NSBundle.mainBundle().URLForResource("bach1", withExtension: "jpg") {
if NSFileManager.defaultManager().fileExistsAtPath(resourceUrl.path!) {
print("file found")
}
}
Swift 3.x
if let resourceUrl = Bundle.main.url(forResource: "bach1", withExtension: "jpg") {
if FileManager.default.fileExists(atPath: resourceUrl.path) {
print("file found")
}
}
I found that you have to actually go into Build Phases -> Copy Bundle Resources and manually add your item sometimes to the bundle. In my case it was a video file that didn't get added to the bundle correctly on its own.
NSBundle.URLForResource only returns files that are bundled in your application at build/compile time, like when you drag a file into your Xcode project and add it to your app target. You can typically use this when your app comes preloaded with resources you need, like images, movies, databases, and other files.
It seems like savepath is a path your application wrote to while running (maybe into your app's Documents directory?). Because of this, the file is outside of the bundle and you will need to store that path/URL somewhere (or build it up again) if you need to reference the file in the future.
I had this issue too. My fix was:
Selecting the file in project navigator
Open the 'File Inspector' (on the right hand side pane)
Checking the app target in the Target Membership