macOS sandbox folder authorization

macOS sandbox folder authorization

If macOS wants to be released on the Apple market, it must comply with Apple's sandbox protocol. In this way, the application's storage defaults to the sandbox path, which isolates the user's file system. At this time, I need to access /User/xxx/Library/ If you use a folder like Developer/, direct access will be denied. In this case, you must authorize it. Once you agree, access will be justified.

So how to perform this operation? The first thing that comes to mind is to open the folder first, then the current permissions will be available, and then solve the problem of still having permissions to access in the future. At this time, bookmark is used. Dongdong is used for this purpose. Let’s implement this function step by step.

This example takes authorizing the /user/xxx/Library/Developer/ path as an example.

First get the absolute path to the file.

func getAbsolutePath(path: String) -> String? {
    
    
    let pw = getpwuid(getuid())
    guard let home = pw?.pointee.pw_dir else {
    
    
        return nil
    }
    let homePath = FileManager.default.string(withFileSystemRepresentation: home, length: Int(strlen(home)))
    return "\(homePath)/\(path)"
}

let path = getAbsolutePath("/Library/Developer")
// /User/xxx/Library/Developer/

Open the folder and get permissions

func openFinder() {
    
    
    let fm = FileManager.default
    let filepath = getAbsolutePath(path: "Library/Developer/")!
    print("filepath is \(filepath)")
    let url = URL(filePath: filepath)
    
    let dialog = NSOpenPanel()
    dialog.message = "文件夹授权以提供服务"
    dialog.prompt = "选择"
    dialog.allowsOtherFileTypes = false
    dialog.canChooseFiles = false
    dialog.canChooseDirectories = true
    dialog.directoryURL = url
    
    dialog.begin {
    
     response in
        if response == .OK, let folderPath = dialog.url {
    
    
            // 可以判断一下是不是想要的文件夹,这个时候已经有权限了。
            // 保存书签权限
        }
    }
}

Save bookmark permissions

Save the bookmark data in the bookmark and retrieve it for later use.

private func saveBookmarkData(for workDir: URL) {
    
    
    do {
    
    
        let bookmarkData = try workDir.bookmarkData(options: .withSecurityScope, includingResourceValuesForKeys: nil, relativeTo: nil)

        print("save book mark data")
        // save in UserDefaults
        UserDefaults.standard.setValue(bookmarkData, forKey: "bookmark")
    } catch {
    
    
        print("Failed to save bookmark data for \(workDir)", error)
    }
}

Determine whether the path is authorized

private func restoreFileAccess() -> Bool {
    
    
    do {
    
    
        if let bookmark = UserDefaults.standard.object(forKey: "bookmark") as? Data {
    
    
            var isStale = false
            let url = try URL(resolvingBookmarkData: bookmark, options: .withSecurityScope, relativeTo: nil, bookmarkDataIsStale: &isStale)
            guard url.startAccessingSecurityScopedResource() else {
    
    
                return false
            }
            return true
        }
        return false
    } catch {
    
    
        print("Error resolving bookmark:", error)
        return false
    }
}

Complete code

The following is the complete code

import SwiftUI

struct ContentView: View {
    
    
    @State var fileSize: Int = 0
    @State var canAccess: Bool = false
    
    func getAbsolutePath(path: String) -> String? {
    
    
        let pw = getpwuid(getuid())
        guard let home = pw?.pointee.pw_dir else {
    
    
            return nil
        }
        let homePath = FileManager.default.string(withFileSystemRepresentation: home, length: Int(strlen(home)))
        return "\(homePath)/\(path)"
    }
    
    private func saveBookmarkData(for workDir: URL) {
    
    
        do {
    
    
            let bookmarkData = try workDir.bookmarkData(options: .withSecurityScope, includingResourceValuesForKeys: nil, relativeTo: nil)

            print("save book mark data")
            // save in UserDefaults
            UserDefaults.standard.setValue(bookmarkData, forKey: "bookmark")
        } catch {
    
    
            print("Failed to save bookmark data for \(workDir)", error)
        }
    }
    
    private func restoreFileAccess() -> Bool {
    
    
        do {
    
    
            if let bookmark = UserDefaults.standard.object(forKey: "bookmark") as? Data {
    
    
                var isStale = false
                let url = try URL(resolvingBookmarkData: bookmark, options: .withSecurityScope, relativeTo: nil, bookmarkDataIsStale: &isStale)
                guard url.startAccessingSecurityScopedResource() else {
    
    
                    return false
                }
                return true
            }
            return false
        } catch {
    
    
            print("Error resolving bookmark:", error)
            return false
        }
    }
    
    func openFinder() {
    
    
        let fm = FileManager.default
        let filepath = getAbsolutePath(path: "Library/Developer/")!
        print("filepath is \(filepath)")
        let url = URL(filePath: filepath)
        
        let dialog = NSOpenPanel()
        dialog.message = "Choose your directory"
        dialog.prompt = "Choose"
        dialog.allowsOtherFileTypes = false
        dialog.canChooseFiles = false
        dialog.canChooseDirectories = true
        dialog.directoryURL = url
        
        dialog.begin {
    
     response in
            if response == .OK, let folderPath = dialog.url {
    
    
                saveBookmarkData(for: folderPath)
            }
        }
    }
    
    var body: some View {
    
    
        VStack {
    
    
            Image(systemName: "globe")
                .imageScale(.large)
                .foregroundStyle(.tint)
            Text("占用容量: \(fileSize)")
            
            Button {
    
    
                if !canAccess {
    
    
                    openFinder()
                }
            } label: {
    
    
                if canAccess {
    
    
                    Text("已授权")
                } else {
    
    
                    Text("授权")
                }
            }
        }
        .padding()
        .onAppear {
    
    
            if restoreFileAccess() {
    
    
                canAccess = true
            } else {
    
    
                canAccess = false
            }
            print("access is \(canAccess)")
        }
    }
}

#Preview {
    
    
    ContentView()
}

Guess you like

Origin blog.csdn.net/xo19882011/article/details/134787254