ios: update the plist to include correct package domain+name, version, build id, and resample the icon if the dimensions are not ok.

This commit is contained in:
Mathieu Virbel 2013-01-23 01:54:30 +01:00
parent fb0741a21f
commit 5f203cf3bb
3 changed files with 94 additions and 3 deletions

View file

@ -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 :(

View file

@ -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')

View file

@ -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'):