簡體   English   中英

在使用 UIKit for macOS (Catalyst) 構建的應用程序中生成進程

[英]Spawning a process in an app built with UIKit for macOS (Catalyst)

我正在構建一個在 macOS 和 iOS 版本之間共享大部分代碼的應用程序(針對 macOS 11 和 iOS 14)。 適用於 Mac 的 UIKit 似乎是解決此問題的自然選擇。 不幸的是,其中一個庫在后台使用Process類型 當添加對它的依賴項以及針對 macOS 時,構建它會產生“無法在范圍內找到類型Process ”錯誤。 我可以排除 iOS 的這個庫,但我仍然需要在 macOS 上鏈接它,同時保持在所有平台上使用 UIKit 的能力。

在此處輸入圖像描述

我已選擇此庫僅在 Xcode 中為 macOS 鏈接,但這沒有任何效果,並且相同的構建錯誤仍然存在。 此外,我沒有在應用程序中添加單個import SwiftLSPClient語句就收到了這個錯誤,所以我認為條件導入在這種情況下不會有幫助。

Xcode 中的框架、庫和嵌入式內容設置

在上面列出的限制范圍內解決此問題的最佳方法是什么?

我在我的 Mac Catalyst 應用程序中創建了一個 LSPCatalyst class 來替換 MacOS LanguageServerProcessHost。 為了完成這項工作,我將process屬性替換為processProxy ,它使用 FoundationApp 協議訪問 MacOS 包中的流程實例,如下所述。

按照@Adam 的建議,我創建了一個 MacOS 包來代理流程實例。 您遵循與他指出的從 Catalyst 應用程序訪問 AppKit 相同的想法,但您只需要 Foundation 即可訪問 Process。 我調用了捆綁包 FoundationGlue 並將所有內容放在我的 Xcode 項目的 FoundationGlue 文件夾中。 該捆綁包需要一個 Info.plist,將主體 class 標識為“FoundationGlue.MacApp”,MacApp.swift 如下所示:

    import Foundation

    class MacApp: NSObject, FoundationApp {
    var process: Process!
    var terminationObserver: NSObjectProtocol!
    
    func initProcess(_ launchPath: String!, _ arguments: [String]?, _ environment: [String : String]?) {
        process = Process()
        process.launchPath = launchPath
        process.arguments = arguments
        process.environment = environment
    }
    
    func setTerminationCompletion(_ completion: (()->Void)!) {
        let terminationCompletion = {
            NotificationCenter.default.removeObserver(self.terminationObserver!)
            completion?()
        }
        terminationObserver =
            NotificationCenter.default.addObserver(
                forName: Process.didTerminateNotification,
                object: process,
                queue: nil) { notification -> Void in
                terminationCompletion()
            }
    }
    
    func setupProcessPipes(_ stdin: Pipe!, _ stdout: Pipe!, _ stderr: Pipe!) {
        process.standardInput = stdin
        process.standardOutput = stdout
        process.standardError = stderr
    }
    
    func launchProcess() {
        process.launch()
        print("Launched process \(process.processIdentifier)")
    }

    func terminateProcess() {
        process.terminate()
    }
    
    func isRunningProcess() -> Bool {
        return process.isRunning
    }

    
}

我調用FoundationApp.h對應的header看起來像:

#import <Foundation/Foundation.h>

@protocol FoundationApp <NSObject>

typedef void (^terminationCompletion) ();
- (void)initProcess: (NSString *) launchPath :(NSArray<NSString *> *) arguments :(NSDictionary<NSString *, NSString *> *) environment;
- (void)setTerminationCompletion: (terminationCompletion) completion;
- (void)setupProcessPipes: (NSPipe *) stdin :(NSPipe *) stdout :(NSPipe *) stderr;
- (void)launchProcess;
- (void)terminateProcess;
- (bool)isRunningProcess;

@end

FoundationAppGlue-Bridging-Header.h 僅包含:

#import "FoundationApp.h"

為 MacOS 構建包后,將其作為框架添加到 Mac Catalyst 項目中。 我在該項目中創建了一個 Catalyst.swift 用於訪問 FoundationGlue 捆綁功能:

import Foundation

@available(macCatalyst 13, *)
struct Catalyst {

    /// Catalyst.foundation gives access to the Foundation functionality identified in FoundationApp.h and implemented in FoundationGlue/MacApp.swift
    static var foundation: FoundationApp! {
        let url = Bundle.main.builtInPlugInsURL?.appendingPathComponent("FoundationGlue.bundle")
        let bundle = Bundle(path: url!.path)!
        bundle.load()
        let cls = bundle.principalClass as! NSObject.Type
        return cls.init() as? FoundationApp
    }
    
}

然后,您可以從您的應用程序中使用它,例如:

let foundationApp = Catalyst.foundation!
foundationApp.initProcess("/bin/sh", ["-c", "echo 1\nsleep 1\necho 2\nsleep 1\necho 3\nsleep 1\necho 4\nsleep 1\nexit\n"], nil)
foundationApp.setTerminationCompletion({print("terminated")})
foundationApp.launchProcess()

這是一個混亂的解決方案,但我知道它有效:將“Mac 捆綁包”添加到您的 Catalyst 應用程序,然后導入僅適用於 MacOS 的框架。

以下是創建和加載 Mac 包的指南: https://medium.com/better-programming/how-to-access-the-appkit-api-from-mac-catalyst-apps-2184527020b5

獲得捆綁包后,您可以向其中添加僅限 Mac 的庫和框架。 您必須在包和您的 iOS 應用程序之間橋接數據和方法調用,但它是可管理的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM