Merge branch 'ipa-installer'

This commit is contained in:
NobyDa 2023-08-16 19:47:31 +08:00
commit be5185e08c
No known key found for this signature in database
GPG Key ID: E6B0AC788D373C5B
7 changed files with 403 additions and 4 deletions

View File

@ -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()
}
})
}

View File

@ -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()

View File

@ -0,0 +1,146 @@
/*
* iOS IPA应用辅助安装脚本.
*
* 兼容: QuantumultXSurge5LoonShadowrocketStash
* 作者: @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)
}
};

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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