Post

Replies

Boosts

Views

Activity

IOSurface with System Extensions
Hi All, I'm working on a camera system extension where the main app is supposed to transfer a video stream using IOSurface memory sharing to the cam extension. I have built a sample app that does contains all the logic, but without a camera extension. So I'm essentially using IOSurface to render a video in one SwiftUI view and show the result in another SwiftUI view. Just for testing purposes. And everything works fine so far. Now, when moving the receiver code to the camera extensions, I'm having problems in accessing the IOSurface via ID. I am sharing the IOSurface ID via UserDefaults. I know from the logs the ID is correctly transferred. Here is the code that uses IOSurfaceLookup to get the IOSurface. But this fails with the given message. The error message prints the surface ID which is the correct one. I know this from the main app where I get the ID and print it as well. private var surfaceId: Int = -1 { didSet { logger.info("surfaceId has changed") if surfaceId == -1 { stopReceivingFrames() ioSurface = nil } else { guard let surface = IOSurfaceLookup(IOSurfaceID(surfaceId)) else { logger.error("failed to lookup IOSurface with ID: \(self.surfaceId)") return } self.ioSurface = surface logger.info("surface set, now starting receiving frames") startReceivingFrames() } } } My gut feeling says that this issue might be related to some missing entitlement, sandboxing. In general, I have a working camera extension. I'm just not able to render a video in the main app, and send it over to the camera extension to overlay another web cam. Both, the main app and camera extension are in the same XCode workspace and share the same AppGroup. In short, my actual questions are: Is there any entitlement required for using IOSurface between app and camera system extension? Is using IOSurface actually possible in system extensions? Is there any specific setting/requirement that I need to handle to make this work?
0
0
67
1d
onDisappear (or similar) for macOS Settings/Preferences screen
Hi All, this question has been asked before by others, without any success so far. I'm using the following (standard) method to open the system provided settings screen for my macOS (only) app in SwiftUI. var body: some Scene { Settings { PreferencesView() } if #available(macOS 13, *) { // MenuBarExtra requires macOS 13, but SettingsLink used in here requires macOS 14 MenuBarExtra("...", image: "...") { ... // this one requires macOS 14 if #available(macOS 14, *) { SettingsLink() { Text("Settings...") } } else { Button { NSApp.sendAction(Selector(("showSettingsWindow:")), to: nil, from: nil) } label: { Image(systemName: "gear") } } } } } I want to know when the settings window closes. onDisappear does not work as the settings window is not really closed, but hidden. So the view stays active. All other hacks I have found neither work. Does anyone have any idea?
2
1
390
Jun ’24
How to open any file with a Swift macOS app
Problem A macOS app built in Swift (using XCode) shall show up in the "Open With" context menu for any file. But it does not show up at all. Current status The app has a document type for public.item defined. <key>CFBundleDocumentTypes</key> <array> <dict> <key>CFBundleTypeName</key> <string>Any file</string> <key>CFBundleTypeRole</key> <string>Editor</string> <key>LSHandlerRank</key> <string>Default</string> <key>LSItemContentTypes</key> <array> <string>public.item</string> </array> <key>NSDocumentClass</key> <string>NSDocument</string> </dict> </array> When I start the app (from XCode), no file has my app in the "Open With" menu. I've seen a lot of tutorials on how to add a custom type. But not any tutorial for a public type. Is this even possible? Actual question: How can I configure a Swift app to show up in the "Open With" menu for any file?
3
0
1.4k
Sep ’23
How to drag an item using NSItemProviderWriting using async
Scenario: The following Swift code uses NSItemProviderWriting to load a file from some data source async (The code actually just uses a for loop to simulate the time it needs to load the file). It returns the file url then. This code is used for drag & drop behavior in a macOS app from an app to another app. As the other app does only support file URLs as drop types, I can't send over the data itself. class AnyFile: NSObject, NSItemProviderWriting { let url: URL init(url: URL) { self.url = url } static var writableTypeIdentifiersForItemProvider: [String] { return [UTType.fileURL.identifier] } func loadData(withTypeIdentifier typeIdentifier: String, forItemProviderCompletionHandler completionHandler: @escaping @Sendable (Data?, Error?) -> Void) -> Progress? { let count = 100000 let progress = Progress(totalUnitCount: Int64(count)) print("a") Task { print("b") for i in 0...100000 { progress.completedUnitCount = Int64(i) print(i) } print("c") completionHandler(url.dataRepresentation, nil) print("d") } print("e") return progress } } Problem: Drag & drop works, but when I start to drag the view (SwiftUI view using .onDrag), the view gets stuck as long as the loop is running. It is not clear to me why this happens as the loop us running inside a task. The console output also shows that progress is returned before the loop as finished. But still, it is stuck until the end of the loop. So the user experience is like not using async and the task. Log output (shortened) a e b 0 ... 100000 c d Actual Question: Why is this Swift code for dragging files not behaving asynchronously even though it uses Task, completionHandler, and async/await constructs? Alternatives tried: I'm not bound to NSItemProviderWriting in particular. I have tried other ways, like Transferable, .draggable(), and NSItemProvider.registerFileRepresentation. But either they won't return a URL, or do not allow async at all. I also tried AppKit instead of SwiftUI with similar issues.
2
0
906
Sep ’23
Drag URL from my app to another using a promise (in Swift)
Hi All, I have successfully implemented drag & drop of files from and to other apps on macOS successfully using different methods. Including NSFilePromiseProvider for example. There is one app however, that I use on a regular basis, that only support file urls as drop types. So I have to use public.file-url to drag & drop files there. The problem is that the file does not exist when dragging starts. That's why I would like to send a URL promise to the app, instead of a file promise. I can't create the file beforehand because then I would need to create hundreds of large files which will just take up space. So whenever I drag an item from my app to the other app, then the file shall be created and the url shall be sent to that app to be opened. But as the other app only checks the pasteboard for urls without handling promises, this is not working. I do have their code available, but can't change the code. Question: Is there a way in Swift on macOS to drag and drop a an item to another app so that upon mouse up on the other app some async tasks is executed and at the end the other app receives the URL as a result of the async task?
0
1
620
Sep ’23
How to create a proper dropdown toolbar item in SwiftUI for macOS?
Hi All, I have a macOS app written in SwiftUI where I want to add a simple drop down button with a menu to the toolbar for a view. It currently looks like this: You can see that there is no gap between the drop down arrow and the symbol. And the icon/symbol color sometimes seems to be grayed out. When the app starts it also shows black sometimes (not constantly reproducible). var body: some Scene { WindowGroup { ContentView() .frame(maxWidth: .infinity, maxHeight: .infinity) .navigationTitle("Title") .toolbar { ToolbarItem(placement: .primaryAction) { Menu { Button { ... } label: { Text("Open cache directory") } .help("Show application support folder") .disabled(applicationSupportDirectory == nil) Button { ... } label: { Text("Clear cache") } .help("Clears all content from the cache") .disabled(applicationSupportDirectory == nil) } label: { Image(systemName: "gear") } } } } .windowToolbarStyle(.unified) } I basically want to have a simple drop down toolbar item with a few menu items. The app is pretty new so it does not have any fancy code just yet. I wonder what I am missing. Looking forward to have a button like this: I tried different symbols, applying padding and frame width on the Image. I tried different placements and ToolbarItemGroup. Strangely enough: When setting the toolbar style to unifiedcompact, at least the spacing works. But the colouring is still strange. Nothing helped so far.
1
1
1.5k
Aug ’23
Control padding in Table cells
Hi all, I'm working on a SwiftUI app (macOS only) that uses a Table to show contents of a directory. Each Table Cell seems to have a padding / gap which I would like to remove. If you look at the picture, I want the red rectangle to fill the whole cell. Does anybody know how to achieve this? Here's my current code for that column: TableColumn("name", value: \.name) { item in HStack { if item.type == .directory { Image(systemName: "folder") .frame(width: 14) } else { Text("") .frame(width: 14) } Text(item.name) Spacer() } .contentShape(Rectangle()) .gesture(TapGesture(count: 2).onEnded { print(item) doubleClick(path: item.path) }).simultaneousGesture(TapGesture().onEnded { self.selectedFileItem = item.id }) .background(.red) .padding(.all, 0) } I want this to be applied to all columns in the table. I only showed one column as a reference. The table style is .tableStyle(.bordered(alternatesRowBackgrounds: true))
0
0
490
Aug ’23
What does Self { Self() } mean?
Hi, I'm following the iOS AppDev Tutorials by Apple, and stumbled upon the following lines of code: struct TrailingIconLabelStyle: LabelStyle {   func makeBody(configuration: Configuration) -> some View {     HStack {       configuration.title       configuration.icon     }   } } extension LabelStyle where Self == TrailingIconLabelStyle {   static var trailingIcon: Self { Self() } } And I have a few questions here. I understand that this is about extending the type LabelStyle. And from the docs, I understand that where Self == TrailingIconLabelStyle means that the extension will only take place on LabelStyle in case the type is TrailingIconLabelStyle. Why do I have to create a separate extension? Why not add trailingIcon to TrailingIconLabelStyle directly? Why is trailingIcon static. Doesn't that mean that all instances always reference the same value? What does Self { Self() } mean? I assume this is some closure that can also be written like Self(x in { Self() }) or so. But I don't really get this.
1
2
783
May ’22
Can't connect players in GameKit using GKMatchmaker.shared().findMatch
I'm trying to connect two players with each other using GameKit in a very simple game. I want to use GKMatchmaker.shared().findMatch as I don't want to show any GameCenter related view controllers. (to keep it simple) Problem: Even though GameKit creates a match after finding two players, an error occurs that prevents either player from sending any message to the others. Current Situation: The basic code is as follows (based on the docs described here: https://developer.apple.com/documentation/gamekit/finding_multiple_players_for_a_game) print("Requesting multiplayer match") let request = GKMatchRequest() request.minPlayers = 2 request.maxPlayers = 2 request.recipientResponseHandler = {(player: GKPlayer, respnse: GKInviteRecipientResponse) -> Void in print("new player about to join") print(player.alias) print(respnse) } GKMatchmaker.shared().findMatch(for: request, withCompletionHandler: { (match: GKMatch?, error: Error?) -> Void in if error != nil { // Handle the error that occurred finding a match. print("error during matchmaking") print(error as Any) } else if match != nil { guard let match = match else { return } print("connected to \(match.players.count) players") // load the multiplayer data handler let handler = MultiMatchHandler() match.delegate = handler // load the multiplayer service let service = MultiMatchService(match: match) service.sendMessageToAll(text: "Hello from the other side") // finish the match making GKMatchmaker.shared().finishMatchmaking(for: match) // Start the game with the players in the match. self.view?.presentScene(GameScene.newScene(multiplayer: service)) } }) The output of that is Requesting multiplayer match 2022-01-05 01:19:16.554959+0100 Grapefruit[38300:10026027] [Match] cannot set connecting state for players: ( "<GKPlayer: 0x282add280>(alias:... gamePlayerID:... teamPlayerID:... name:... status:(null) friendBiDirectional:0 friendPlayedWith:1 friendPlayedNearby:0 acceptedGameInviteFromThisFriend:0 initiatedGameInviteToThisFriend:0 automatchedTogether:1)" ), as there is no inviteDelegate set yet. The state might directly change to Ready when we set the inviteDelegate later and call sendQueuedStatesAndPackets. 2022-01-05 01:19:16.557002+0100 Grapefruit[38300:10026027] [Match] syncPlayers failed to loadPlayersForLegacyIdentifiers: ( "..." ) connected to 0 players sending text Hello from the other side failed Findings: minPlayers is set to 2. As the completion handler is called this means that at least one more player was found. But the number of players returned in match.players.count is 0 The matcher shows an error saying that cannot set connecting state for players ... as there is no inviteDelegate set yet. I can't find any info about this invite delegate. Actual Question: What is an inviteDelegate? Do I really need to implement such (if yes, then how?)? (I don't think so as the docs state that the match only starts after the invites are accepted). How can I resolve this issue?
0
0
894
Jan ’22