Sursă publicată
Descarcă sursa ZIP
CH-J SM Mobile
Navighează directoarele și fișierele pentru o anumită versiune a aplicației.
CH-J / SM Mobile
134 fișiere
sm-mobile-20261016T050549Z-3678f2a05fa9
Adăugat: · Construit:
1
#!/usr/bin/env python32
"""Package a built mobile release and allowlisted source without signing secrets.4
Run tool/build.py distribution first. This script does not build or deploy.5
"""6
import datetime7
import hashlib8
import json9
from pathlib import Path10
import re11
import shutil12
import subprocess13
import tempfile14
import zipfile16
ROOT = Path(__file__).resolve().parents[1]17
WORKSPACE = ROOT.parent18
INFO = (ROOT / 'lib/core/build_info.dart').read_text()19
BUILD_ID = re.search(r"const buildId = '([^']+)'", INFO).group(1)20
VERSION = re.search(r"const appVersion = '([^']+)'", INFO).group(1)21
if not re.fullmatch(r'sm-mobile-\d{8}T\d{6}Z-[a-f0-9]{12}', BUILD_ID):22
raise SystemExit('Invalid build ID')23
RELEASE = WORKSPACE / 'POUZE-VYVOJOVA-DATA-BEZ-ZAVISLOSTI-NA-APP/builds' / BUILD_ID24
RELEASE.mkdir(exist_ok=False)25
FILES = RELEASE / 'source/files'26
FILES.mkdir(parents=True)28
# Explicit roots; local SDK configuration and generated Xcode configuration are excluded.29
selected = [ROOT / name for name in [30
'README.md', 'LICENSE', 'NOTICE', 'pubspec.yaml', 'pubspec.lock',31
'analysis_options.yaml', 'l10n.yaml', '.gitignore', '.metadata',32
'android/build.gradle.kts', 'android/settings.gradle.kts', 'android/gradle.properties',33
'android/gradlew', 'android/gradlew.bat', 'android/app/build.gradle.kts',34
'ios/Flutter/AppFrameworkInfo.plist', 'ios/Flutter/Debug.xcconfig', 'ios/Flutter/Release.xcconfig',35
'ios/Runner.xcodeproj/project.pbxproj', 'ios/Runner.xcworkspace/contents.xcworkspacedata',36
]]37
for folder in ['lib', 'assets', 'docs', 'test', 'integration_test', 'tool',38
'android/gradle/wrapper', 'android/app/src', 'ios/Runner', 'ios/RunnerTests',39
'ios/Runner.xcodeproj/xcshareddata', 'ios/Runner.xcworkspace/xcshareddata']:40
selected.extend((ROOT / folder).rglob('*'))41
entries = []42
for source in sorted(set(selected)):43
if source.is_symlink():44
raise SystemExit('Symlink in source allowlist: ' + str(source))45
if not source.is_file():46
continue47
relative = source.relative_to(ROOT)48
if source.name.startswith('.') and source.name not in ['.gitignore', '.metadata']:49
continue50
if any(part in ['__pycache__', '.dart_tool', 'build', 'ephemeral', '.swiftpm', 'xcuserdata'] for part in relative.parts):51
continue52
if source.name in ['GeneratedPluginRegistrant.java', 'GeneratedPluginRegistrant.h', 'GeneratedPluginRegistrant.m']:53
continue54
if source.suffix.lower() in ['.jks', '.keystore', '.mobileprovision', '.p12', '.p8', '.pem', '.key', '.pyc'] or source.name in ['key.properties', 'local.properties', 'Generated.xcconfig', 'flutter_export_environment.sh']:55
raise SystemExit('Private or machine-specific file in source allowlist: ' + str(relative))56
if not re.fullmatch(r'[A-Za-z0-9_@.\/-]+', relative.as_posix()):57
raise SystemExit('Unsupported source browser path: ' + str(relative))58
data = source.read_bytes()59
destination = FILES / relative60
destination.parent.mkdir(parents=True, exist_ok=True)61
destination.write_bytes(data)62
destination.chmod(0o755 if source.name == 'gradlew' else 0o644)63
try:64
text = data.decode('utf-8')65
is_text = '\0' not in text66
except UnicodeDecodeError:67
text, is_text = '', False68
entries.append(dict(path=relative.as_posix(), size=len(data), sha256=hashlib.sha256(data).hexdigest(),69
text=is_text, lines=len(text.splitlines()) if is_text else None))70
archive = RELEASE / f'CH-J-SM-Mobile-{VERSION}-{BUILD_ID}-source.zip'71
with zipfile.ZipFile(archive, 'w', zipfile.ZIP_DEFLATED, compresslevel=9) as handle:72
for entry in entries:73
handle.write(FILES / entry['path'], 'app/' + entry['path'])74
built_at = datetime.datetime.strptime(BUILD_ID.split('-')[2], '%Y%m%dT%H%M%SZ').replace(tzinfo=datetime.timezone.utc).isoformat()75
manifest = dict(buildId=BUILD_ID, version=VERSION, edition='mobile', builtAt=built_at,76
addedAt=datetime.datetime.now(datetime.timezone.utc).isoformat(),77
license='CH-J Proprietary Software License 1.14', archive=archive.name,78
archiveSize=archive.stat().st_size, archiveSha256=hashlib.sha256(archive.read_bytes()).hexdigest(), files=entries)79
(RELEASE / 'source/manifest.json').write_text(json.dumps(manifest, ensure_ascii=False, indent=2) + '\n')81
artifacts = []82
def add(path, kind, platform, arch, signing, certificate=None):83
data = path.read_bytes()84
entry = dict(id=hashlib.sha256((BUILD_ID + ':' + kind).encode()).hexdigest()[:24],85
type='mobile', kind=kind, active=True, version=VERSION, build_id=BUILD_ID,86
platform=platform, arch=arch, signing=signing, channel='alpha', artifact_role='installer',87
filename=path.name, file=f'files/mobile/{BUILD_ID}/{path.name}', size=len(data),88
sha512=hashlib.sha512(data).hexdigest(), sha256=hashlib.sha256(data).hexdigest(),89
published_at=manifest['addedAt'])90
if certificate:91
entry['certificateSha256'] = certificate92
artifacts.append(entry)94
# Verify APK signature using the same Java runtime as the Flutter Android toolchain.95
import os96
java_home = '/opt/homebrew/opt/openjdk@17/libexec/openjdk.jdk/Contents/Home'97
android_sdk = Path(dict(line.split('=', 1) for line in (ROOT / 'android/local.properties').read_text().splitlines() if '=' in line)['sdk.dir'])98
checker = sorted((android_sdk / 'build-tools').glob('*/apksigner'))[-1]99
signature = subprocess.check_output([str(checker), 'verify', '--verbose', '--print-certs', str(ROOT / 'build/app/outputs/flutter-apk/app-release.apk')], env={**os.environ, 'JAVA_HOME': java_home}, text=True)100
(RELEASE / 'android-signature.txt').write_text(signature)101
certificate = re.search(r'Signer #1 certificate SHA-256 digest: ([a-f0-9]+)', signature).group(1)102
for kind, original in [('apk', 'build/app/outputs/flutter-apk/app-release.apk'), ('aab', 'build/app/outputs/bundle/release/app-release.aab')]:103
destination = RELEASE / f'CH-J-SM-Mobile-{VERSION}-{BUILD_ID}.{kind}'104
shutil.copyfile(ROOT / original, destination)105
add(destination, kind, 'android', 'arm64-v8a / armeabi-v7a / x86_64', 'android-release', certificate)107
# ZIP the actual device .app under Payload without inventing an Apple signature.108
ipa = RELEASE / f'CH-J-SM-Mobile-{VERSION}-{BUILD_ID}-unsigned.ipa'109
with tempfile.TemporaryDirectory() as temporary:110
payload = Path(temporary) / 'Payload'111
payload.mkdir()112
subprocess.run(['ditto', str(ROOT / 'build/ios/iphoneos/Runner.app'), str(payload / 'Runner.app')], check=True)113
subprocess.run(['ditto', '-c', '-k', '--keepParent', str(payload), str(ipa)], check=True)114
add(ipa, 'ipa', 'ios', 'arm64', 'unsigned')115
simulator = ROOT / 'build/ios/iphonesimulator/Runner.app'116
if simulator.is_dir():117
destination = RELEASE / f'CH-J-SM-Mobile-{VERSION}-{BUILD_ID}-simulator.app.zip'118
subprocess.run(['ditto', '-c', '-k', '--keepParent', str(simulator), str(destination)], check=True)119
add(destination, 'simulator', 'ios-simulator', 'arm64', 'simulator-only')120
(RELEASE / 'mobile-release.json').write_text(json.dumps(dict(buildId=BUILD_ID, version=VERSION, artifacts=artifacts), indent=2) + '\n')121
(RELEASE / 'SHA512SUMS.txt').write_text(''.join(f"{entry['sha512']} {entry['filename']}\n" for entry in artifacts) + hashlib.sha512(archive.read_bytes()).hexdigest() + ' ' + archive.name + '\n')122
print(json.dumps(dict(release=str(RELEASE), buildId=BUILD_ID, files=len(entries), artifacts=len(artifacts))))SHA-256
f811f21c261a3eab38be61b3e30694a7729803bcc95b7a29d4ba35708addac1eCH-J Proprietary Software License 1.14 · Sursa este furnizată în cadrul CH-J Proprietary Software License 1.14. Disponibilitatea sa nu modifică termenii licenţei sau nu acordă drepturi suplimentare.
Archive SHA-256
c486a807e4828998b9c57ab0f2e760f7980b31965fe118e89d3e1a5a2b65be65