Russ
Russ

Reputation: 576

Connect to MacOS Network Share from IOS using Swift

I'm clearly missing something. I would like to do something similar to the Files app in iOS where I can traverse a network server's file tree starting at a share point. I can access the share in the actual Files app just fine but cannot seem to replicate that in my own app. If I test this app in the simulator I can access the file tree on the machine where the simulator resides but the same app on a device can't get to the server's share.

In the example below, the function to connect is below the UI code and in it I first try to call FileManager.default.mountedVolumeURLs and when that fails, which it always does, I call FileManager.default.contentsOfDirectory which demonstrates the above mentioned behavior.

import SwiftUI
import Foundation

struct NetFilesView: View
{
    @State var urls: [URL] = []
    
    @State var serverType = "afp"
    @State var server = "server"
    @State var share = ""
    @State var user = ""
    @State var password = ""
    
    @State var errormsg = "Enter server, share, user and password"
    
    
    var body: some View
    {
        VStack
        {
            HStack
            {
                VStack
                {
                    HStack
                    {
                        HStack
                        {
                            Picker("Server type", selection: $serverType)
                            {
                                ForEach("afp,smb,nfs".components(separatedBy: ","), id: \.self)
                                {
                                    Text($0)
                                }
                            }
                            TextField("Server", text: $server)
                                .autocapitalization(.none)
                        }
                        SecureField("User", text: $user).autocapitalization(.none)
                    }
                    HStack
                    {
                        TextField("Share", text: $share)
                            .autocapitalization(.none)
                        SecureField("Password", text: $password)
                            .autocapitalization(.none)
                    }
                }
                Button("Go")
                {
                    do
                    {
                        urls = try connectToNetworkDrive(shareType: serverType, serverAddress: server, sharePath: share, user: (user == "") ? nil : user, password: (password == "") ? nil : password)
                        errormsg = "Success"
                    }
                    catch
                    {
                        errormsg = error.localizedDescription
                    }
                }.buttonStyle(.bordered).tint(Color.green)
            }
            .padding()
            .border(Color.red, width: 1)
            
            
            List(urls, id:\.self)
            { url in
                Text(url.lastPathComponent)
                    .onTapGesture
                {
                    do
                    {
                        if let isDir = (try url.resourceValues(forKeys: [.isDirectoryKey])).isDirectory
                        {
                            if !isDir
                            {
                                // do something with file
                            } else
                            {
                                share = url.relativeString.replacingOccurrences(of: "file:///", with: "").removingPercentEncoding ?? ""
                            }
                        }
                    }
                    catch
                    {
                        errormsg = error.localizedDescription
                    }
                }
                .id(url.lastPathComponent)
                
                //self.returnFunction(url)
                
            }
            Text(errormsg)
                .background(Color.red).foregroundStyle(Color.white)
        }
            .padding()
        }
}

#Preview
{
    NetFilesView()
}

func connectToNetworkDrive(shareType: String = "afp", serverAddress: String, sharePath: String, user: String? = nil, password: String? = nil) throws -> [URL]
{

    var uc = URLComponents()
    uc.scheme = shareType
    uc.host = serverAddress
    uc.path = (sharePath.starts(with: "/")) ? sharePath : "/" + sharePath
    uc.user = user
    uc.password = password
    print(uc.url ?? "Bad URL")
    
    if let networkDriveURL = uc.url
    {
        if let urls = FileManager.default.mountedVolumeURLs(includingResourceValuesForKeys: nil)
        {
            let isMounted = urls.contains(where: { $0.path == networkDriveURL.path })
            
            if !isMounted
            {
                print("Network drive not mounted")
            } else
            {
                print("Network drive successfully accessed")
                return urls
            }
        } else
        {
            print("No share at: \(networkDriveURL.absoluteString)")
        }
        
        let urls = try FileManager.default.contentsOfDirectory(at: networkDriveURL, includingPropertiesForKeys: nil)
        
        return urls
    }
    return []
}

Upvotes: 0

Views: 25

Answers (0)

Related Questions