跳至主要內容

建立一個執行任務 (sys.task)

聲明

任務 = sys.task(可執行檔案路徑 [, 參數...])

參數

  • 可執行檔案路徑
    文字型
  • 參數...
    文字型,可選不定參數,預設沒有

回傳值

  • 任務
    執行任務物件,返回一個控制任務或執行任務的物件

任務物件方法清單

方法參數回傳值說明
:launch()啟動任務,異步運行
:wait_until_exit()同步等待任務結束,任務結束前會阻塞所有執行緒。
:set_stdin(輸入流)管道 | 文字型設定任務的輸入流。參數可以是 "std""/dev/null"、檔案路徑、管道物件。任務啟動後再呼叫將拋出錯誤
:stdin()管道 | 文字型取得任務的輸入流。可能返回 "std""/dev/null"、檔案路徑、管道物件
:set_stdout(輸出流)管道 | 文字型設定任務的輸出流。參數可以是 "std""/dev/null"、檔案路徑、管道物件。任務啟動後再呼叫將拋出錯誤
:stdout()管道 | 文字型取得任務的輸出流。可能返回 "std""/dev/null"、檔案路徑、管道物件
:set_stderr(錯誤流)管道 | 文字型設定任務的錯誤流。參數可以是 "std""/dev/null"、檔案路徑、管道物件。任務啟動後再呼叫將拋出錯誤
:stderr()管道 | 文字型取得任務的錯誤流。可能返回 "std""/dev/null"、檔案路徑、管道物件
:set_work_dir(目錄)文字型設定任務的工作目錄。任務啟動後再呼叫將拋出錯誤
:work_dir()文字型取得任務的工作目錄
:set_env(環境變數)表型設定任務的環境變數鍵值詞典。任務啟動後再呼叫將拋出錯誤
:env()表型取得任務的環境變數鍵值詞典
:pid()整數型取得任務的行程號,任務啟動前取得返回 0
:is_running()布林型判斷任務是否正在運行。即使 :is_running() 返回 false,也應當對任務呼叫一次 :wait_until_exit() 以阻止產生僵屍行程
:interrupt()布林型向任務主行程發送終止 SIGINT 信號
:terminate()布林型向任務主行程發送終止 SIGTERM 信號
:kill()布林型向任務所有行程發送強殺 SIGKILL 信號,任務物件被回收時會自動執行 kill 操作
:termination_status()整數型取得任務的終止狀態,如果任務尚未結束則返回 nil, 錯誤資訊
:termination_reason()文字型取得任務的終止原因,如果任務尚未結束則返回 nil, 錯誤資訊

管道物件方法清單

方法參數回傳值說明
:read()字串型從管道中讀取已經準備好的資料
:write(資料)字串型向管道中寫入資料
:wclose()布林型, nil | 文字型關閉管道寫端,成功返回 true,失敗返回 false, 錯誤資訊
:rclose()布林型, nil | 文字型關閉管道讀端,成功返回 true,失敗返回 false, 錯誤資訊

說明

建立一個執行任務,返回一個執行任務物件
若不希望阻塞所有執行緒等待任務完成,可循環呼叫任務物件的 :is_running() 判斷任務是否仍在運行;待其結束後,再呼叫一次 :wait_until_exit() 以確認任務已終止
該函式在 20250705 以後版本方可使用

範例

-- 模擬以下 Shell 命令
-- echo "你好世界" | /usr/bin/gzip -fc | /usr/bin/gzip -dfc

local comp_tsk = sys.task(jbroot('/usr/bin/gzip'), '-fc') -- 創建壓縮任務
local decomp_tsk = sys.task(jbroot('/usr/bin/gzip'), '-dfc') -- 創建解壓任務

decomp_tsk:set_stdin(comp_tsk:stdout()) -- 設置解壓任務的輸入流為壓縮任務的輸出流

decomp_tsk:launch() -- 啓動解壓任務
comp_tsk:launch() -- 啓動壓縮任務

comp_tsk:stdin():write("你好世界") -- 向壓縮任務的輸入流寫入數據
comp_tsk:stdin():wclose() -- 關閉壓縮任務的輸入流寫端,表示輸入流已經結束

comp_tsk:wait_until_exit() -- 等待壓縮任務結束
decomp_tsk:wait_until_exit() -- 等待解壓任務結束

nLog(decomp_tsk:stdout():read()) -- 讀取解壓任務的輸出流,輸出 "你好世界"

範例(呼叫巨魔持久助手重新整理)

local persistence_helper_path = app.bundle_path('com.apple.tips')
if not persistence_helper_path then
nLog('没有检测到 Tips.app,请先从 AppStore 安装 Tips(提示)应用')
return
end
local root_helper_path = persistence_helper_path..'/trollstorehelper'
if file.exists(root_helper_path) ~= 'file' then
nLog('未注入巨魔持久助手到 Tips,请先从 TrollStore -> Settings -> Install Persistence Helper 选择 Tips 注入')
return
end
local tsk = sys.task(root_helper_path, 'refresh')
tsk:launch()
tsk:wait_until_exit()
sys.killall(9, 'SpringBoard', 'backboardd')

範例(呼叫巨魔安裝卸載 App,重建圖示快取)

local function _trollstorehelper(...)
local troll_path = app.bundle_path('com.opa334.TrollStore')
assert(type(troll_path) == 'string', 'TrollStore needs to be installed.')
local tsk = sys.task(troll_path..'/trollstorehelper', ...)
tsk:set_stdin('/dev/null')
tsk:launch()
local outbuf = {}
local errbuf = {}
local function drain_stream(stream, buf)
local data = stream:read('nb')
if data and #data > 0 then
buf[#buf + 1] = data
end
end
while tsk:is_running() do
drain_stream(tsk:stdout(), outbuf)
drain_stream(tsk:stderr(), errbuf)
sys.msleep(100)
end
tsk:wait_until_exit()
drain_stream(tsk:stdout(), outbuf)
drain_stream(tsk:stderr(), errbuf)
if tsk:termination_status() == 0 then
local ret = table.concat(outbuf)
return ret
else
local ret = table.concat(errbuf)
return nil, ret
end
end

--- 使用 TrollStore 安裝一個 App
---@param ipapath string 安裝包路徑
---@return string? 安裝結果文本,失敗返回 nil
---@return string? 錯誤信息,成功返回 nil
function troll_install(ipapath)
return _trollstorehelper('install', ipapath)
end

--- 卸載 TrollStore 安裝的 App
---@param bid string 應用包標識符
---@return string? 卸載結果文本,失敗返回 nil
---@return string? 錯誤信息,成功返回 nil
function troll_uninstall(bid)
return _trollstorehelper('uninstall', bid)
end

--- TrollStore 重建圖標緩存,會需要消耗一些時間
---@return string? 重建結果文本,失敗返回 nil
---@return string? 錯誤信息,成功返回 nil
function troll_rebuild_icon_cache()
return _trollstorehelper('refresh-all')
end

-- 示例調用
nLog(troll_install(XXT_SCRIPTS_PATH..'/TrollDecrypt.tipa')) -- 安裝 TrollDecrypt
nLog(troll_uninstall('com.fiore.trolldecrypt')) -- 卸載 TrollDecrypt
nLog(troll_rebuild_icon_cache()) -- 重建圖標緩存