mirror of https://github.com/NobyDa/Script.git
Merge branch 'ipa-installer'
This commit is contained in:
commit
be5185e08c
|
@ -0,0 +1,144 @@
|
|||
/*
|
||||
* IPA-installer JSBox script. This script is not available stand alone, checkout the demo from TG channel @NobyDa
|
||||
*
|
||||
* Modified from https://github.com/axelburks/JSBox/blob/master/IPA%20Installer.js by @NobyDa
|
||||
*/
|
||||
|
||||
var port_number = 8070
|
||||
var plist_url = `itms-services://?action=download-manifest&url=https://nobyda.app/install%3Fclient%3Djsbox%26url%3Dhttp%253A%252F%252F127.0.0.1%253A${port_number}%252Fdownload%253Fpath%253D%25252Fapp.ipa`
|
||||
|
||||
$app.strings = {
|
||||
"en": {
|
||||
"starterror": "Not support running in this way",
|
||||
"ftypeerror": " is not ipa file",
|
||||
"installtitle": "Installing...",
|
||||
"installmsg": "\n\nYou can check on Homescreen.\nPlease tap \"Done\" button after finished",
|
||||
"inerrtitle": "IPA file import error",
|
||||
"inerrmsg": "Please rerun the script"
|
||||
},
|
||||
"zh-Hans": {
|
||||
"starterror": "不支持此方式运行!",
|
||||
"ftypeerror": " 非 ipa 文件!",
|
||||
"installtitle": "正在安装…",
|
||||
"installmsg": "\n\n可前往桌面查看安装进度\n完成后请点击\"Done\"按钮",
|
||||
"inerrtitle": "IPA文件导入失败",
|
||||
"inerrmsg": "请重新运行此脚本"
|
||||
}
|
||||
}
|
||||
|
||||
// 从应用内启动
|
||||
if ($app.env == $env.app) {
|
||||
$drive.open({
|
||||
handler: function(data) {
|
||||
fileCheck(data)
|
||||
}
|
||||
})
|
||||
}
|
||||
// 从 Action Entension 启动
|
||||
else if ($app.env == $env.action) {
|
||||
fileCheck($context.data)
|
||||
}
|
||||
|
||||
else {
|
||||
$ui.error($l10n("starterror"))
|
||||
delayClose(2)
|
||||
}
|
||||
|
||||
|
||||
function startServer(port) {
|
||||
$http.startServer({
|
||||
port: port,
|
||||
path: "",
|
||||
handler: function(result) {
|
||||
console.info(result.url)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function fileCheck(data) {
|
||||
if (data && data.fileName) {
|
||||
var fileName = data.fileName;
|
||||
if (fileName.indexOf(".ipa") == -1) {
|
||||
$ui.error(fileName + $l10n("ftypeerror"))
|
||||
delayClose(2)
|
||||
} else {
|
||||
install(fileName, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function install(fileName, file) {
|
||||
var result = $file.write({
|
||||
data: file,
|
||||
path: "app.ipa"
|
||||
})
|
||||
if (result) {
|
||||
startServer(port_number)
|
||||
$location.startUpdates({
|
||||
handler: function(resp) {
|
||||
console.info(resp.lat + " " + resp.lng + " " + resp.alt)
|
||||
}
|
||||
})
|
||||
var preResult = $app.openURL(plist_url);
|
||||
if (preResult) {
|
||||
$ui.alert({
|
||||
title: $l10n("installtitle"),
|
||||
message: "\n" + fileName + $l10n("installmsg"),
|
||||
actions: [{
|
||||
title: "Cancel",
|
||||
style: "Cancel",
|
||||
handler: function() {
|
||||
$http.stopServer()
|
||||
$file.delete("app.ipa")
|
||||
delayClose(0.2)
|
||||
}
|
||||
},
|
||||
{
|
||||
title: "Done",
|
||||
handler: function() {
|
||||
$http.stopServer()
|
||||
$file.delete("app.ipa")
|
||||
delayClose(0.2)
|
||||
}
|
||||
}]
|
||||
})
|
||||
} else {
|
||||
$ui.alert({
|
||||
title: "Open itms-services scheme failed",
|
||||
message: "Please rerun the script or restart device",
|
||||
actions: [
|
||||
{
|
||||
title: "OK",
|
||||
handler: function() {
|
||||
delayClose(0.2)
|
||||
}
|
||||
}]
|
||||
})
|
||||
}
|
||||
} else {
|
||||
$ui.alert({
|
||||
title: $l10n("inerrtitle"),
|
||||
message: $l10n("inerrmsg"),
|
||||
actions: [{
|
||||
title: "OK",
|
||||
style: "Cancel",
|
||||
handler: function() {
|
||||
delayClose(0.2)
|
||||
}
|
||||
}]
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function delayClose(time) {
|
||||
$location.stopUpdates()
|
||||
$thread.main({
|
||||
delay: time,
|
||||
handler: function() {
|
||||
if ($app.env == $env.action || $app.env == $env.safari) {
|
||||
$context.close()
|
||||
}
|
||||
$app.close()
|
||||
}
|
||||
})
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
# IPA-installer pythonista script. This script is not available stand alone, checkout the demo from TG channel @NobyDa
|
||||
#
|
||||
# Modified from https://github.com/axelburks/Pythonista/blob/master/IPA%20Installer.py by @NobyDa
|
||||
|
||||
import os, appex, console, shutil, http.server, webbrowser, time
|
||||
from os import path
|
||||
from threading import Thread
|
||||
|
||||
port_number = 8090
|
||||
plist_url = f'itms-services://?action=download-manifest&url=https://nobyda.app/install%3Fclient%3Dpythonista%26url%3Dhttp%253A%252F%252F127.0.0.1%253A{port_number}%252Fipa%252Fapp.ipa'
|
||||
save_dir = path.expanduser('./ipa')
|
||||
if not path.exists(save_dir):
|
||||
os.makedirs(save_dir)
|
||||
|
||||
httpd = None
|
||||
def startServer(port):
|
||||
Handler = http.server.SimpleHTTPRequestHandler
|
||||
|
||||
global httpd
|
||||
httpd = http.server.HTTPServer(("", port), Handler)
|
||||
|
||||
print("Start server at port", port)
|
||||
httpd.serve_forever()
|
||||
|
||||
def start(port):
|
||||
thread = Thread(target=startServer, args=[port])
|
||||
thread.start()
|
||||
|
||||
startTime = int(time.time())
|
||||
while not httpd:
|
||||
if int(time.time()) > startTime + 60:
|
||||
print("Time out")
|
||||
break
|
||||
return httpd
|
||||
|
||||
def stop():
|
||||
if httpd:
|
||||
httpd.shutdown()
|
||||
|
||||
def main():
|
||||
if appex.is_running_extension():
|
||||
get_path = appex.get_file_path()
|
||||
file_name = path.basename(get_path)
|
||||
file_ext = path.splitext(file_name)[-1]
|
||||
if file_ext == '.ipa':
|
||||
dstpath = path.join(save_dir, 'app.ipa')
|
||||
try:
|
||||
shutil.copy(get_path, dstpath)
|
||||
|
||||
except Exception as eer:
|
||||
print(eer)
|
||||
console.hud_alert('导入失败!','error',1)
|
||||
start(port_number)
|
||||
if httpd:
|
||||
webbrowser.open(plist_url)
|
||||
try:
|
||||
finish = console.alert(file_name, '\n正在安装...请返回桌面查看进度...\n\n安装完成后请返回点击已完成','已完成', hide_cancel_button=False)
|
||||
if finish == 1:
|
||||
stop()
|
||||
shutil.rmtree('./ipa')
|
||||
print("Server stopped")
|
||||
except:
|
||||
stop()
|
||||
shutil.rmtree('./ipa')
|
||||
print("Cancelled")
|
||||
appex.finish()
|
||||
else:
|
||||
console.hud_alert('非 ipa 文件无法导入安装', 'error', 2)
|
||||
appex.finish()
|
||||
else:
|
||||
console.hud_alert('请在分享扩展中打开本脚本','error',2)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
|
@ -0,0 +1,146 @@
|
|||
/*
|
||||
* iOS IPA应用辅助安装脚本.
|
||||
*
|
||||
* 兼容: QuantumultX、Surge5,Loon、Shadowrocket、Stash
|
||||
* 作者: @NobyDa
|
||||
*
|
||||
* 快捷指令 + Shu配合安装:
|
||||
* 导入IPA文件至Shu -> Shu长按IPA文件 -> 导出文件 -> WiFi传输 -> 本机 -> 系统共享 -> 分享至IPA-Installer快捷指令
|
||||
*
|
||||
* 快捷指令 + JSBox/Pythonista配合安装:
|
||||
* IPA文件长按分享至IPA-Installer快捷指令,完成后再分享至Jsbox/pythonista分享扩展.
|
||||
*
|
||||
*
|
||||
* QuanX重写: https://raw.githubusercontent.com/NobyDa/Script/master/QuantumultX/IPA-Installer.snippet
|
||||
*
|
||||
* Surge模块: https://raw.githubusercontent.com/NobyDa/Script/master/Surge/Module/IPA_install.sgmodule
|
||||
*
|
||||
* loon插件: https://raw.githubusercontent.com/NobyDa/Script/master/Loon/Loon_IPA_Installer.plugin
|
||||
*
|
||||
* Stash覆写: https://raw.githubusercontent.com/NobyDa/Script/master/Stash/IPA-Installer.stoverride
|
||||
*
|
||||
* 快捷指令: https://www.icloud.com/shortcuts/a89979261837465aa3b4cae3527cf5f9
|
||||
*
|
||||
* JSBox脚本: https://xteko.com/redir?url=https%3A%2F%2Fraw.githubusercontent.com%2FNobyDa%2FScript%2Fmaster%2FIPA-Installer%2FIPA-Installer-JSBox.js&name=IPA%20Installer%20%28NobyDa%29
|
||||
*
|
||||
* Pythonista脚本: https://github.com/NobyDa/Script/blob/master/IPA-Installer/IPA-Installer-Pythonista.py
|
||||
*/
|
||||
|
||||
const $ = new compatible_tool();
|
||||
|
||||
(async function () {
|
||||
const args = urlArgs($request.url);
|
||||
const plist = `<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>items</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>assets</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>kind</key>
|
||||
<string>software-package</string>
|
||||
<key>url</key>
|
||||
<string>https://nobyda.app/download?url=${encodeURIComponent(args.url)}</string>
|
||||
</dict>
|
||||
</array>
|
||||
<key>metadata</key>
|
||||
<dict>
|
||||
<key>bundle-identifier</key>
|
||||
<string>${args.bundleId || $.read("nobyda_ipa_bundle_id") || "*"}</string>
|
||||
<key>bundle-version</key>
|
||||
<string>1.0</string>
|
||||
<key>kind</key>
|
||||
<string>software</string>
|
||||
<key>title</key>
|
||||
<string>IPA</string>
|
||||
</dict>
|
||||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>`;
|
||||
if ($request.url.includes("/install?")) {
|
||||
if (args.bundleId) {
|
||||
$.write(args.bundleId, "nobyda_ipa_bundle_id");
|
||||
};
|
||||
$.resp = { response: { status: 200, body: args.client && plist || "{}" } };
|
||||
} else {
|
||||
if ($request.method == "GET") {
|
||||
const size = await ipaSize(args.url);
|
||||
$.notify(`IPA Installer`, ``, size && `Installing IPA, Size: ${size} MB` || `HTTP local server read failed!`);
|
||||
}
|
||||
$.resp = { response: { status: 307, headers: { Location: args.url }, body: "{}" } };
|
||||
}
|
||||
})()
|
||||
.catch((e) => $.notify(`IPA Installer`, ``, `ERROR: ${e.message || e}\nPATH: ${e.stack}`))
|
||||
.finally(() => $.done($.resp))
|
||||
|
||||
|
||||
function ipaSize(url) {
|
||||
return new Promise((r, e) => {
|
||||
$.http({ method: "head", url: url, policy: "DIRECT", }, (e, h, d) => {
|
||||
r(h && h.status == 200 && `${((h.headers["Content-Length"] || 0) / 1000 / 1000).toFixed(2)}`)
|
||||
});
|
||||
setTimeout(() => r(), 1000)
|
||||
});
|
||||
}
|
||||
|
||||
function urlArgs(str) {
|
||||
return Object.fromEntries(
|
||||
(str.startsWith("http") && str.split("?")[1] || str).split("&")
|
||||
.map((item) => item.split("="))
|
||||
.map(([k, v]) => [k, decodeURIComponent(v)])
|
||||
);
|
||||
}
|
||||
|
||||
function compatible_tool() {
|
||||
const isSurge = typeof $httpClient != "undefined";
|
||||
const isQuanX = typeof $task != "undefined";
|
||||
const isStash = typeof $environment == "object" && $environment["stash-version"];
|
||||
const adapterStatus = (response) => {
|
||||
if (response && response.statusCode) {
|
||||
response.status = response.statusCode;
|
||||
}
|
||||
return response
|
||||
};
|
||||
this.read = (key) => {
|
||||
if (isQuanX) return $prefs.valueForKey(key);
|
||||
if (isSurge) return $persistentStore.read(key);
|
||||
};
|
||||
this.write = (value, key) => {
|
||||
if (isQuanX) return $prefs.setValueForKey(value, key);
|
||||
if (isSurge) return $persistentStore.write(value, key);
|
||||
};
|
||||
this.notify = (title, subtitle, message) => {
|
||||
if (isQuanX) $notify(title, subtitle, message);
|
||||
if (isSurge) $notification.post(title, subtitle, message);
|
||||
};
|
||||
this.http = (options, callback) => {
|
||||
if (options.policy) {
|
||||
options.node = options.policy;
|
||||
options.opts = { policy: options.policy };
|
||||
if (isStash) options.headers = {
|
||||
...options.headers,
|
||||
...{ "X-Stash-Selected-Proxy": encodeURIComponent(options.policy) }
|
||||
};
|
||||
}
|
||||
if (isQuanX) {
|
||||
$task.fetch(options).then(response => {
|
||||
callback(null, adapterStatus(response), response.body)
|
||||
}, reason => callback(reason.error, null, null))
|
||||
}
|
||||
if (isSurge) {
|
||||
$httpClient[options.method](options, (error, response, body) => {
|
||||
callback(error, adapterStatus(response), body)
|
||||
})
|
||||
}
|
||||
};
|
||||
this.done = (value = {}) => {
|
||||
if (value.response && isQuanX) {
|
||||
value.response.status = `HTTP/1.1 ${value.response.status}`;
|
||||
}
|
||||
$done((value.response && isQuanX) ? value.response : value)
|
||||
}
|
||||
};
|
|
@ -0,0 +1,12 @@
|
|||
#!name=IPA应用辅助安装器
|
||||
#!desc=该模块可在iOS端辅助安装商店版或已签名IPA(需使用快捷指令 + Shu/Jsbox/pythonista), 查看脚本注释以了解具体方法; 安装演示可查看TG频道 @NobyDa
|
||||
#!author=NobyDa
|
||||
#!homepage=https://github.com/NobyDa/Script/tree/master
|
||||
#!icon=https://cdn.jsdelivr.net/gh/NobyDa/mini@master/Color/Apple.png
|
||||
|
||||
|
||||
[Script]
|
||||
http-request ^https:\/\/nobyda.app/(install|download) requires-body=true, script-path=https://raw.githubusercontent.com/NobyDa/Script/master/IPA-Installer/IPA-Installer.js, timeout=10, tag=IPA-Installer
|
||||
|
||||
[MITM]
|
||||
hostname = nobyda.app
|
|
@ -0,0 +1,6 @@
|
|||
# 该文件为 "IPA应用辅助安装脚本" QuantumultX远端重写资源.
|
||||
# 该资源可在iOS端辅助安装商店版或已签名IPA(需使用快捷指令 + Shu/Jsbox/pythonista), 查看脚本注释以了解具体方法; 安装演示可查看TG频道 @NobyDa
|
||||
|
||||
^https:\/\/nobyda.app/(install|download) url script-analyze-echo-response https://raw.githubusercontent.com/NobyDa/Script/master/IPA-Installer/IPA-Installer.js
|
||||
|
||||
hostname = nobyda.app
|
|
@ -0,0 +1,16 @@
|
|||
name: IPA应用辅助安装器
|
||||
desc: 该模块可在iOS端辅助安装商店版或已签名IPA(需使用快捷指令 + Shu/Jsbox/pythonista), 查看脚本注释以了解具体方法; 安装演示可查看TG频道 @NobyDa
|
||||
|
||||
http:
|
||||
mitm:
|
||||
- nobyda.app
|
||||
script:
|
||||
- match: ^https:\/\/nobyda.app/(install|download)
|
||||
name: IPA-Installer
|
||||
type: request
|
||||
require-body: true
|
||||
timeout: 10
|
||||
script-providers:
|
||||
IPA-Installer:
|
||||
url: https://raw.githubusercontent.com/NobyDa/Script/master/IPA-Installer/IPA-Installer.js
|
||||
interval: 86400
|
|
@ -1,8 +1,9 @@
|
|||
#!name=iOS14 IPA应用安装
|
||||
#!desc=该模块可解决iOS14或IPadOS14无法在移动端安装IPA的问题. 注: 需要使用Shu+捷径或Jsbox辅助安装.
|
||||
#!name=IPA应用辅助安装器
|
||||
#!desc=该模块可在iOS端辅助安装商店版或已签名IPA(需使用快捷指令 + Shu/Jsbox/pythonista), 查看脚本注释以了解具体方法; 安装演示可查看TG频道 @NobyDa
|
||||
|
||||
|
||||
[Script]
|
||||
IPA应用安装 = type=http-request,pattern=^https:\/\/nobyda/(install|download)(\/jsbox)?$,requires-body=1,max-size=0,script-path=https://raw.githubusercontent.com/NobyDa/Script/master/Surge/JS/IPA_install.js
|
||||
IPA Installer = type=http-request,pattern=^https:\/\/nobyda.app/(install|download),requires-body=1,script-path=https://raw.githubusercontent.com/NobyDa/Script/master/IPA-Installer/IPA-Installer.js
|
||||
|
||||
[MITM]
|
||||
hostname = %APPEND% nobyda
|
||||
hostname = %APPEND% nobyda.app
|
Loading…
Reference in New Issue