From 5f203cf3bb7c4e7f50ef7e5d081308e568b4bfc3 Mon Sep 17 00:00:00 2001 From: Mathieu Virbel Date: Wed, 23 Jan 2013 01:54:30 +0100 Subject: [PATCH] ios: update the plist to include correct package domain+name, version, build id, and resample the icon if the dimensions are not ok. --- buildozer/__init__.py | 18 ++++++++- buildozer/targets/android.py | 2 +- buildozer/targets/ios.py | 77 +++++++++++++++++++++++++++++++++++- 3 files changed, 94 insertions(+), 3 deletions(-) diff --git a/buildozer/__init__.py b/buildozer/__init__.py index 3f7eb7c..4358b2f 100644 --- a/buildozer/__init__.py +++ b/buildozer/__init__.py @@ -53,6 +53,7 @@ class Buildozer(object): self.environ = {} self.specfilename = filename self.state = None + self.build_id = None self.config = SafeConfigParser() self.config.getlist = self._get_config_list self.config.getdefault = self._get_config_default @@ -122,7 +123,15 @@ class Buildozer(object): if hasattr(self.target, '_build_done'): return - self.info('Build the application') + # increment the build number + self.build_id = int(self.state.get('cache.build_id', '0')) + 1 + self.state['cache.build_id'] = str(self.build_id) + # FIXME WHY the hell we need to close/reopen the state to sync the build + # id ??? + self.state.close() + self.state = shelve.open(join(self.buildozer_dir, 'state.db')) + + self.info('Build the application #{}'.format(self.build_id)) self.build_application() self.info('Package the application') @@ -384,6 +393,13 @@ class Buildozer(object): self.debug('Rename {0} to {1}'.format(source, target)) rename(source, target) + def file_copy(self, source, target, cwd=None): + if cwd: + source = join(cwd, source) + target = join(cwd, target) + self.debug('Copy {0} to {1}'.format(source, target)) + copyfile(source, target) + def file_extract(self, archive, cwd=None): if archive.endswith('.tgz') or archive.endswith('.tar.gz'): # XXX tarfile doesn't work for NDK-r8c :( diff --git a/buildozer/targets/android.py b/buildozer/targets/android.py index 7038a96..5ae6dc6 100644 --- a/buildozer/targets/android.py +++ b/buildozer/targets/android.py @@ -338,7 +338,7 @@ class TargetAndroid(Target): package = config.get('app', 'package.name') if package_domain: package = package_domain + '.' + package - return package + return package.lower() def build_package(self): dist_dir = join(self.pa_dir, 'dist', 'default') diff --git a/buildozer/targets/ios.py b/buildozer/targets/ios.py index 710cc1c..0432887 100644 --- a/buildozer/targets/ios.py +++ b/buildozer/targets/ios.py @@ -2,6 +2,7 @@ iOS target, based on kivy-ios project. (not working yet.) ''' +import plistlib from buildozer.target import Target from os.path import join, basename @@ -57,6 +58,14 @@ class TargetIos(Target): if not self.buildozer.file_exists(self.fruitstrap_dir, 'fruitstrap'): self.buildozer.cmd('make fruitstrap', cwd=self.fruitstrap_dir) + def _get_package(self): + config = self.buildozer.config + package_domain = config.getdefault('app', 'package.domain', '') + package = config.get('app', 'package.name') + if package_domain: + package = package_domain + '.' + package + return package.lower() + def build_package(self): # create the project app_name = self.buildozer.namify(self.buildozer.config.get('app', 'title')) @@ -71,6 +80,27 @@ class TargetIos(Target): app_name, self.buildozer.app_dir), cwd=self.ios_dir) + # fix the plist + plist_fn = '{}-Info.plist'.format(app_name.lower()) + plist_rfn = join(self.app_project_dir, plist_fn) + version = self.buildozer.get_version() + self.buildozer.info('Update Plist {}'.format(plist_fn)) + plist = plistlib.readPlist(plist_rfn) + plist['CFBundleIdentifier'] = self._get_package() + plist['CFBundleShortVersionString'] = version + plist['CFBundleVersion'] = '{}.{}'.format(version, + self.buildozer.build_id) + + # add icon + icon = self._get_icon() + if icon: + plist['CFBundleIconFiles'] = [icon] + plist['CFBundleIcons'] = {'CFBundlePrimaryIcon': { + 'UIPrerenderedIcon': False, 'CFBundleIconFiles': [icon]}} + + # ok, write the modified plist. + plistlib.writePlist(plist, plist_rfn) + mode = 'Debug' if self.build_mode == 'debug' else 'Release' self.buildozer.cmd('xcodebuild -configuration {}'.format(mode), cwd=self.app_project_dir) @@ -83,10 +113,10 @@ class TargetIos(Target): if not ioscodesign: self.buildozer.error('Cannot create the IPA package without' ' signature. You must fill the "{}" token.'.format(key)) + return elif ioscodesign[0] not in ('"', "'"): ioscodesign = '"{}"'.format(ioscodesign) - version = self.buildozer.get_version() ipa = join(self.buildozer.bin_dir, '{}-{}.ipa'.format( app_name, version)) self.buildozer.cmd(( @@ -117,6 +147,7 @@ class TargetIos(Target): if 'ios:latestappdir' not in state: self.buildozer.error( 'App not built yet. Run "debug" or "release" first.') + return ios_app_dir = state.get('ios:latestappdir') if gdb: @@ -131,6 +162,50 @@ class TargetIos(Target): gdb=gdb_mode, app_dir=ios_app_dir), cwd=self.ios_dir, show_output=True) + def _get_icon(self): + # check the icon size, must be 72x72 or 144x144 + icon = self.buildozer.config.getdefault('app', 'icon.filename', '') + if not icon: + return + icon_fn = join(self.buildozer.app_dir, icon) + if not self.buildozer.file_exists(icon_fn): + self.buildozer.error('Icon {} does not exists'.format(icon_fn)) + return + output = self.buildozer.cmd('file {}'.format(icon), + cwd=self.buildozer.app_dir, get_stdout=True)[0] + if not output: + self.buildozer.error('Unable to read icon {}'.format(icon_fn)) + return + # output is something like: + # "data/cancel.png: PNG image data, 50 x 50, 8-bit/color RGBA, + # non-interlaced" + info = output.splitlines()[0].split(',') + fmt = info[0].split(':')[-1].strip() + if fmt != 'PNG image data': + self.buildozer.error('Only PNG icon are accepted, {} invalid'.format(icon_fn)) + return + size = [int(x.strip()) for x in info[1].split('x')] + if size != [72, 72] and size != [144, 144]: + # icon cannot be used like that, it need a resize. + self.buildozer.error('Invalid PNG size, must be 72x72 or 144x144. Resampling.') + nearest_size = 144 + if size[0] < 144: + nearest_size = 72 + + icon_basename = 'icon-{}.png'.format(nearest_size) + self.buildozer.file_copy(icon_fn, join(self.app_project_dir, + icon_basename)) + self.buildozer.cmd('sips -z {0} {0} {1}'.format(nearest_size, + icon_basename), cwd=self.app_project_dir) + else: + # icon ok, use it as it. + icon_basename = 'icon-{}.png'.format(size[0]) + self.buildozer.file_copy(icon_fn, join(self.app_project_dir, + icon_basename)) + + icon_fn = join(self.app_project_dir, icon_basename) + return icon_fn + def check_configuration_tokens(self): errors = [] if not self.buildozer.config.getdefault('app', 'ios.codesign.debug'):