Python fir 下载脚本兼容iOS
思路
方法一:类似Android处理,用接口下载文件后,直接通过数据线进行安装
方法二:通过服务端返回下载URL,iOS用快捷指令处理
最后选取的第二种方法。对之前脚本做如下修改:
1 新增平台参数,补充对应分支token
2 因Android有渠道包判断,所以增加判断:若为iOS平台,则无需判断changelog
3 根据fir提供文档,处理iOS URL
import requests, os, time
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
from pathlib import Path
from tqdm import tqdm
from threading import Thread
from time import time
from urllib.parse import urlencode, quote_plus
from urllib.parse import quote
downloadPath = Path.cwd().parent.parent.parent.joinpath("apk", "download")
def Interrupt_exception(func):
'''
定义一个装饰器:
捕捉手动停止错误
'''
def wrapper(*args, **kwargs):
try:
result = func(*args, **kwargs)
return result
except KeyboardInterrupt:
print("手动停止")
os._exit(0)
return wrapper
class myloadApk():
def __init__(self, platform, which, version=None, bulid=None, changelog="Inner"):
self.platform = platform
self.which = which
self.version = version
self.build = bulid
self.changelog = changelog
self.thread_num = 3
self.url = None
self.total_size = None
@Interrupt_exception
def findApk(self):
'''
查找下载APP id
'''
for i in range(1, 10):
print("正在查询第" + str(i) + "页")
url = "http://fir-api.fircli.cn/apps/" + self.id + "/releases?api_token=" + self.api_token + "&page=" + str(
i)
respones = requests.get(url, verify=False)
allHistory = respones.json()['datas']
for build_version in allHistory:
print(build_version["version"])
print(build_version["build"])
print(build_version["changelog"])
print(build_version["id"])
print("--------********---------")
if (self.version == None or build_version["version"] == self.version) and (
self.build == None or build_version["build"] == self.build) and (
self.changelog in build_version["changelog"] or self.platform == "iOS"):
self.version = build_version["version"]
self.build = build_version["build"]
return build_version["id"]
def download_token(self):
'''
获取download_token
'''
url = "http://api.bq04.com/apps/" + self.id + "/download_token?api_token=" + self.api_token
respones = requests.get(url, verify=False)
return respones.json()['download_token']
def bytes_format(self, value):
'''
文件大小自转换
'''
units = ["B", "KB", "MB", "GB", "TB", "PB"]
size = 1024.0
for i in range(len(units)):
if (value / size) < 1:
return "%.2f%s" % (value, units[i])
value = value / size
def get_url(self):
'''
获取下载url
'''
down_token = self.download_token()
releaseid = self.findApk()
print("%s : %s(%s) %s" % (self.which, self.version, self.build, self.changelog))
url = "http://download.bq04.com/apps/" + self.id + "/install?download_token=" + down_token + "&release_id=" + releaseid
return url
def get_iOSurl(self):
'''
获取下载 iOSurl
'''
down_token = self.download_token()
releaseid = self.findApk()
print("%s : %s(%s) %s" % (self.which, self.version, self.build, self.changelog))
url = "https://download.bq04.com/apps/" + self.id + "/install?download_token=" + down_token + "&release_id=" + releaseid
return "itms-services://?action=download-manifest&url=" + quote_plus(url)
def get_total_size(self):
'''
获取下载文件大小
'''
Response = requests.get(self.url, stream=True, verify=False)
# 总大小
total_size = int(Response.headers.get('content-length', 0))
print(self.bytes_format(total_size))
return total_size
@Interrupt_exception
def loadAPK(self):
'''
单线程下载ing
'''
start = time()
self.url = self.get_url()
self.total_size = self.get_total_size()
paths = str(downloadPath) + "/HelloTalk_" + self.version + "_" + self.build + "_" + self.which + ".apk"
# stream=True的作用是仅让响应头被下载,连接保持打开状态,
if Path(paths).exists():
temp_size = os.path.getsize(paths)
print("已下载文件 " + self.bytes_format(temp_size))
else:
temp_size = 0
if temp_size >= self.total_size:
print("下载完成")
return paths
header = {"Range": f"bytes={temp_size}-{self.total_size}"}
Req = requests.get(self.url, headers=header, stream=True, verify=False, timeout=10)
with open(paths, "ab") as file, tqdm(
initial=temp_size,
desc="正在下载",
total=self.total_size,
unit='',
unit_scale=True,
unit_divisor=1024,
) as bar:
for data in Req.iter_content(chunk_size=1024): # 边下载边存硬盘
size = file.write(data)
bar.update(size)
end = time()
print('总共耗费了%.2f秒.' % (end - start))
return paths
@Interrupt_exception
def adb_install(self):
'''
安装ing
'''
# try:
file_names = self.loadAPK()
print("正在安装...")
cmd_shell = "adb -d install -r -d " + file_names
openApp = os.system(cmd_shell)
if openApp == 0:
os.system("adb -d shell am start -n com.hellotalk/.lib.main.launch.ui.LaunchActivity")
# except:
# self.checking()
优势
无需连接,可以直接下载
劣势
公司网络不稳定,导致需要手动切换网络or更改IP
总结
快捷指令🐮
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)