File indexing completed on 2024-03-24 03:51:17
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)