Files
carinha-control-panel/android/build-apk.py

68 lines
3.5 KiB
Python

"""Build Windows/Linux usando JDK e Android SDK existentes; sem Gradle."""
import argparse
import os
from pathlib import Path
import shutil
import subprocess
import tempfile
import zipfile
HERE = Path(__file__).resolve().parent
DEFAULT_TOOLS = os.environ.get('CARINHA_TOOLS', 'C:/Users/JullioPC/Documents/Open/orange-pi-zero3/android/tools')
def main():
parser = argparse.ArgumentParser()
parser.add_argument('--tools', default=DEFAULT_TOOLS)
args = parser.parse_args()
tools = Path(args.tools)
suffix = '.exe' if os.name == 'nt' else ''
java = tools / 'jdk/bin' / ('java' + suffix)
javac = tools / 'jdk/bin' / ('javac' + suffix)
bt = tools / 'android-sdk/build-tools/34.0.0'
android = tools / 'android-sdk/platforms/android-34/android.jar'
for path in (java, javac, android, bt / ('aapt2' + suffix), HERE / 'keystore.jks'):
if not path.exists():
raise SystemExit('Arquivo necessário não encontrado: ' + str(path))
work = HERE.parents[2] / 'work'
work.mkdir(parents=True, exist_ok=True)
def run(*command):
subprocess.run([str(x) for x in command], check=True)
for name in ('carinha.html', 'camera.html'):
shutil.copy2(HERE.parent / name, HERE / 'app/assets' / name)
with tempfile.TemporaryDirectory(prefix='carinha-build-', dir=work) as folder:
tmp = Path(folder)
for name in ('compiled', 'classes', 'gen'):
(tmp / name).mkdir()
print('Recursos e manifesto', flush=True)
run(bt / ('aapt2' + suffix), 'compile', '--dir', HERE / 'app/res', '-o', tmp / 'compiled/res.zip')
run(bt / ('aapt2' + suffix), 'link', '-o', tmp / 'base.apk', '-I', android,
'--manifest', HERE / 'app/AndroidManifest.xml', '-A', HERE / 'app/assets',
'--java', tmp / 'gen', '--min-sdk-version', '21', '--target-sdk-version', '34', tmp / 'compiled/res.zip')
sources = list((HERE / 'app/java').rglob('*.java')) + list((tmp / 'gen').rglob('*.java'))
print('Java e DEX', flush=True)
run(javac, '--release', '8', '-nowarn', '-classpath', android, '-d', tmp / 'classes', *sources)
classes = list((tmp / 'classes').rglob('*.class'))
run(java, '-cp', bt / 'lib/d8.jar', 'com.android.tools.r8.D8', '--lib', android,
'--min-api', '21', '--output', tmp, *classes)
with zipfile.ZipFile(tmp / 'base.apk', 'a', zipfile.ZIP_DEFLATED) as z:
z.write(tmp / 'classes.dex', 'classes.dex')
for native in (HERE / 'app/native/arm64-v8a').glob('*.so'):
z.write(native, 'lib/arm64-v8a/' + native.name)
run(bt / ('zipalign' + suffix), '-f', '-p', '4', tmp / 'base.apk', tmp / 'aligned.apk')
print('Assinatura persistente', flush=True)
run(java, '-jar', bt / 'lib/apksigner.jar', 'sign', '--ks', HERE / 'keystore.jks',
'--ks-pass', 'pass:android', '--key-pass', 'pass:android', '--ks-key-alias', 'carinha',
'--out', HERE / 'carinha-rosto.apk', tmp / 'aligned.apk')
run(java, '-jar', bt / 'lib/apksigner.jar', 'verify', HERE / 'carinha-rosto.apk')
with zipfile.ZipFile(HERE / 'carinha-rosto.apk') as z:
required = {'AndroidManifest.xml', 'classes.dex', 'resources.arsc', 'assets/carinha.html', 'assets/camera.html', 'assets/transmissao.html', 'assets/qualidade-auto.js'}
assert required.issubset(z.namelist()), 'APK incompleto'
print('APK pronto: ' + str(HERE / 'carinha-rosto.apk'))
if __name__ == '__main__':
main()