Всегда ли процесс не решен в приложении iOS или на игровой площадке? - PullRequest
0 голосов
/ 13 сентября 2018

В приложении для iOS я хочу использовать файл, который имеет следующую функцию, используя Process:

public func system(_ body: String) throws {
    if #available(macOS 10.0, *) {
        let process = Process()

        ...

    } else {
        fatalError()
    }
}

Затем я получил ошибку, несмотря на то, что применил Условие доступности, и я не вызываю эту функцию: Использование неразрешенного идентификатора «Процесс».

Я попробовал подобный код в Playground, и я получил ту же ошибку.

Я узнал, что мы не можем использовать Process в iOS-приложениях обычным образом по этому вопросу: Как выполнять команды терминала в Swift 4? , и у меня есть решение, которое разделяет эти коды с файлами по каждому используя платформы. Но я хочу использовать этот единственный файл, если смогу.

Пожалуйста, дайте мне ваше другое решение для моего идеала.

Ответы [ 2 ]

0 голосов
/ 17 июня 2019

Даже если вы уже решили эту проблему, просто чтобы вы знали, я хочу сказать, что на самом деле Process() (или CommandLine() в Swift 3.0 или новее) доступно для iOS, но вам нужно используйте пользовательский заголовочный файл Objective C , который создает объект Process() / CommandLine(), а точнее NSTask(), и все, что ему нужно.

Затем, чтобы использовать этот код со Swift, вам нужно создать Bridging-Header , в который вам нужно будет импортировать файл NSTask.h, чтобы он был открыт для Swift и возможность использовать его в своем коде Swift.

После этого используйте NSTask() вместо Process():

let process = NSTask() /* or NSTask.init() */

Или просто используйте следующую функцию в своем коде всякий раз, когда вы хотите запустить задачу:

func task(launchPath: String, arguments: String...) -> NSString {
    let task = NSTask.init()
    task?.setLaunchPath(launchPath)
    task?.arguments = arguments

    // Create a Pipe and make the task
    // put all the output there
    let pipe = Pipe()
    task?.standardOutput = pipe

    // Launch the task
    task?.launch()
    task?.waitUntilExit()

    // Get the data
    let data = pipe.fileHandleForReading.readDataToEndOfFile()
    let output = NSString(data: data, encoding: String.Encoding.utf8.rawValue)

    return output!
}

Как видите, NSTask() будет эквивалентно Process() в этом случае.

И назовите это так:

task(launchPath: "/usr/bin/echo", arguments: "Hello World")

Это также вернет значение, так что вы даже можете отобразить его, выполнив:

print(task(launchPath: "/usr/bin/echo", arguments: "Hello, World!"))

Который напечатает:

~> Hello, World!

Чтобы это работало, а не выкидывало NSInternalInconsistencyException, вам нужно установить для launchPath полный путь к исполняемому файлу, а не просто каталог, содержащий его.

Вам также необходимо установить все аргументы команды, разделенные запятыми .

Протестировано на iPad Mini 2 ( iOS 12.1 ~> Jailbroken ) и iPhone Xr ( iOS 12.2 ~> not jailbroken ).

ПРИМЕЧАНИЕ : Несмотря на то, что это работает как на устройствах без джейлбрейка, так и с джейлбрейком, ваше приложение будет отклонено в AppStore, как @ ClausJørgensen сказал:

Вы используете частные API, поэтому он будет отклонен в App Store. Кроме того, Xcode 11 имеет некоторые новые функциональные возможности, которые вызывают сбой сборки при использовании определенных частных API.

Если ваше приложение предназначено для взломанных устройств iOS и будет загружено в сторонний магазин, такой как Cydia, Zebra, Thunderbolt или Sileo, то это будет работать правильно.

Надеюсь, это поможет вам.

0 голосов
/ 13 сентября 2018

if #available() выполняет проверку времени выполнения для версий ОС.

if #available(macOS 10.0, *)

оценивается как true, если код работает на macOS 10.0 или более поздней версии, или на iOS / tvOS / watchOS с ОС, которая является как минимум минимальной целью развертывания.

Требуется условная компиляция , в зависимости от платформы:

#if os(macOS)
let process = Process()
#else
// ...
#endif
...