Home > Back-end >  SwiftUI execute script on click and return output on view window
SwiftUI execute script on click and return output on view window

Time:12-18

I am newbie in SwiftUI. I have intermediate level knowledge on Python and Shell Script. Trying to make an App that basically run backup job to copy data from my MacOS to Network drive. I was able to achieve that using AppleScript integrating Python script earlier but now I am trying to implement same function with an interesting view.

With below code I am trying to create a function that can call a shell script on click (Prefer to store the script inside the App) from any location (Unfortunately not seeing any native solution for Python in SwiftUI) and return realtime output on view window. The code I am writing is for MacOS and not for iPhone basically.

Can anyone please help me guide through right direction please.

import SwiftUI
import Foundation

enum ViewState {
    case DefaultView
    case BackupTaskView
}

struct BackupView : View {
   @State var showing : ViewState = .DefaultView
    
    var body: some View {
        HeaderView()
        VStack {
            if showing == .DefaultView {
                DefaultView(showing:$showing)
            }
            if showing == .BackupTaskView {
                BackupTaskView(showing:$showing)
            }
        }
        .frame(width: 700, height: .infinity, alignment: .topLeading)
        .padding(8)
        
        Spacer()
        FooterView()
    }
}

private struct DefaultView: View {
    
    @Binding var showing : ViewState
    
    @State var navigated = false
    @State var result : String = ""
    
    var body: some View {
        VStack {
            Text(
                "Hello, World!"
            )
        }
        .frame(width: 700, height: .infinity, alignment: .topLeading)
        .padding(8)

        Spacer()

        VStack {
            Button(
                action: { self.showing = .BackupTaskView }
            )
            {
                Image("backup")
                    .resizable()
                    .frame(maxWidth: 180, maxHeight: 180)
            }
            .buttonStyle(PlainButtonStyle())
        }
        
        Spacer()
    }
}

private struct BackupTaskView : View {
    @Binding var showing : ViewState
    @State var result : String = ""
    
    @State var script = "/Users/samiron/Documents/Backup.sh"
    @State var isRunning = false
    
    var body: some View {
        
        VStack {
            Form {
                Section {
                    Text("\(result)")
                }
                .onAppear{self.executeCommand()}
            }
        }
    }
    
    func executeCommand() -> (String?) {
        let task = Process()

        task.launchPath = "/bin/sh"
        task.arguments = [ script ]

        let pipe = Pipe()
        task.standardOutput = pipe
        task.launch()

        let data = pipe.fileHandleForReading.readDataToEndOfFile()
        let result = String(data: data, encoding: .utf8)
        task.waitUntilExit()
        
        return result
    }
}

struct BackupView_Previews: PreviewProvider {
    static var previews: some View {
        BackupView()
    }
}

CodePudding user response:

I assume you wanted something, like

Section {
    Text("\(result)")
}
.onAppear{
  self.result = "Executing..."
  DispatchQueue.global(qos: .background).async {
     let output = self.executeCommand()        // << run in background
     DispatchQueue.main.async {
        self.result = output ?? "Failed"       // << update UI on main
     }
  }
}
  • Related