File indexing completed on 2024-04-28 15:14:28

0001 #!/usr/bin/env python3
0002 # -*- coding: utf-8 -*-
0003 
0004 # SPDX-License-Identifier: LGPL-2.1-or-later
0005 #
0006 # SPDX-FileCopyrightText: 2015 Dennis Nienhüser <nienhueser@kde.org>
0007 #
0008 
0009 import os
0010 import sys
0011 import argparse
0012 from subprocess import call
0013 import tempfile
0014 import shutil
0015 
0016 class Filter(object):
0017     '''
0018     Decides which files to include in the APK
0019     '''
0020 
0021     def __init__(self, base):
0022         self.base = base.rstrip(os.sep)
0023 
0024     def shouldPackage(self, dir, files):
0025         # Change absolute directory name to one relative to the installation directory
0026         dir = dir.replace(self.base, '', 1)
0027 
0028         if dir == '':
0029             # Would not end up in the package, but is slightly faster
0030             return ['include']
0031         if dir == '/assets/data':
0032             # Currently not used
0033             return ['mwdbii', 'weather', 'flags']
0034         elif dir == '/assets/data/maps':
0035             # Other planets are not used
0036             return ['moon']
0037         elif dir == '/assets/data/maps/earth':
0038             # Unused map themes
0039             return ['srtm', 'bluemarble', 'precip-dec', 'citylights', 'plain', 'schagen1689', 'political']
0040         elif dir == '/assets/data/maps/earth/openstreetmap':
0041             # Large images from example KML tour
0042             return [item for item in files if item.endswith('.png') or item.endswith('.jpg')]
0043         elif dir == '/assets/data/placemarks':
0044             # Moon placemarks
0045             return ['moonlandingsites.cache', 'moonterrain.cache']
0046         elif dir == '/assets/data/placemarks':
0047             # Large images. worldmap.svg is used by the overviewmap, bring back if that plugin should be enabled
0048             return ['application-x-marble.svg', 'marsmap.svg', 'marble-logo.svg', 'lunarmap.svg', 'worldmap.svg']
0049         elif dir == '/assets/plugins':
0050             # Whitelisted plugins, all others are ignored
0051             search = ['LatLonPlugin', 'LocalDatabasePlugin']
0052             fileFormats = ['CachePlugin', 'KmlPlugin', 'Pn2Plugin']
0053             floatItems = ['License']
0054             positioning = ['QtPositioningPositionProviderPlugin']
0055             background = ['StarsPlugin', 'AtmospherePlugin']
0056             plugins = search + fileFormats + floatItems + positioning + background
0057             whitelist = set(['lib{}.so'.format(plugin) for plugin in plugins])
0058             masked = [item for item in files if item not in whitelist]
0059             if len(files) - len(masked) != len(whitelist):
0060                 print ('Warning: At least one white-listed plugin is not installed')
0061             return masked
0062         elif dir.startswith('/libs/'):
0063             # other android app binary
0064             return ['libMarble.so']
0065 
0066         return []
0067 
0068 qtDir = os.environ.get('Qt5_android')
0069 if qtDir is None:
0070     print ('Please setup the Qt5_android environment variable point to your Qt installation')
0071     sys.exit(1)
0072 
0073 parser = argparse.ArgumentParser(description='Create an Android application package (APK) for Marble Maps')
0074 parser.add_argument('--target', help='Target filename (or directory) for the .apk package')
0075 parser.add_argument('--keystore', help='Keystore file for signing the package')
0076 parser.add_argument('--storepass', help='Keystore password for signing the package')
0077 parser.add_argument('--release', action='store_true', help='Build a release package')
0078 parser.add_argument('--install', action='store_true', help='Install the package to a connected device (uninstalling it before, if needed)')
0079 parser.add_argument('--reinstall', action='store_true', help='Install the package to a connected device (keeping previous data intact, if any)')
0080 parser.add_argument('directory', help='The directory where the Android build is installed to')
0081 args = parser.parse_args()
0082 
0083 # Sanity check for given options
0084 if not args.install and not args.reinstall and args.target is None:
0085     print('Please pass one of --install, --reinstall or --target to either install the package directly or store it locally.')
0086     sys.exit(1)
0087 jsonFile = os.path.join(args.directory, 'share', 'deploy-behaim.json')
0088 if not os.path.isfile(jsonFile):
0089     print('Cannot find {}. Is {} really a Marble Android installation?'.format(jsonFile, args.directory))
0090     sys.exit(1)
0091 
0092 # Gather needed tools
0093 deployExe = os.path.join(qtDir, 'bin', 'androiddeployqt')
0094 antExe = os.environ.get('ANT', '/usr/bin/ant')
0095 
0096 with tempfile.TemporaryDirectory() as tempDir:
0097     os.rmdir(tempDir) #  shutil.copytree does not like directories to exist
0098     filter = Filter(args.directory)
0099     shutil.copytree(args.directory, tempDir, ignore=filter.shouldPackage)
0100     deployOptions = ['--verbose', '--output', tempDir, '--input', jsonFile, '--ant', antExe]
0101 
0102     # Debug vs. release type packages, signing options
0103     if args.release or args.keystore is not None:
0104         deployOptions.append('--release')
0105     if args.keystore is not None:
0106         deployOptions.append('--sign')
0107         deployOptions.append(args.keystore)
0108         deployOptions.append('Marble')
0109         deployOptions.append('--tsa')
0110         deployOptions.append('http://timestamp.digicert.com')
0111     if args.storepass is not None:
0112         deployOptions.append('--storepass')
0113         deployOptions.append(args.storepass)
0114 
0115     # Options for installing the created package to a connected device
0116     if args.install:
0117         deployOptions.append('--install')
0118     if args.reinstall:
0119         deployOptions.append('--reinstall')
0120     call([deployExe] + deployOptions)
0121 
0122     if args.target is not None:
0123         packageType = 'debug'
0124         if args.keystore is not None:
0125             packageType = 'release-signed'
0126         elif args.release:
0127             packageType = 'release-unsigned'
0128 
0129         targetFile = os.path.join(tempDir, 'bin', 'QtApp-{}.apk'.format(packageType))
0130         if os.path.isfile(targetFile):
0131             shutil.copy(targetFile, args.target)
0132             print ('Created APK at ' + args.target)
0133         else:
0134             sys.exit(1)