From fb0741a21f88a45c6c7769d6825046a458a6c73f Mon Sep 17 00:00:00 2001 From: Mathieu Virbel Date: Tue, 22 Jan 2013 18:36:00 +0100 Subject: [PATCH] add ios support. compilation, packaging, deploy and running works, all from command line. Marvelous!! --- buildozer/__init__.py | 1 + buildozer/default.spec | 12 +++++ buildozer/targets/ios.py | 106 +++++++++++++++++++++++++++++++++++---- 3 files changed, 109 insertions(+), 10 deletions(-) diff --git a/buildozer/__init__.py b/buildozer/__init__.py index 1f11204..3f7eb7c 100644 --- a/buildozer/__init__.py +++ b/buildozer/__init__.py @@ -582,6 +582,7 @@ class Buildozer(object): fromlist=['buildozer']) yield target, m except: + raise pass def usage(self): diff --git a/buildozer/default.spec b/buildozer/default.spec index bdc947e..7dc8bd5 100644 --- a/buildozer/default.spec +++ b/buildozer/default.spec @@ -62,6 +62,18 @@ requirements = twisted,kivy # (str) Android entry point, default is ok for Kivy-based app #android.entrypoint = org.renpy.android.PythonActivity + +# +# iOS specific +# + +# (str) Name of the certificate to use for signing the debug version +#ios.codesign.debug = "iPhone Developer: ()" + +# (str) Name of the certificate to use for signing the release version +#ios.codesign.release = %(ios.codesign.debug)s + + [buildozer] # (int) Log level (0 = error only, 1 = info, 2 = debug (with command output)) diff --git a/buildozer/targets/ios.py b/buildozer/targets/ios.py index 471f7ad..710cc1c 100644 --- a/buildozer/targets/ios.py +++ b/buildozer/targets/ios.py @@ -3,7 +3,7 @@ iOS target, based on kivy-ios project. (not working yet.) ''' from buildozer.target import Target -from os.path import join +from os.path import join, basename class TargetIos(Target): @@ -16,15 +16,17 @@ class TargetIos(Target): checkbin('Git git', 'git') self.buildozer.debug('Check availability of a iPhone SDK') - sdk = cmd('xcodebuild -showsdks | fgrep "iphoneos" | tail -n 1 | awk \'{print $2}\'')[0] + sdk = cmd('xcodebuild -showsdks | fgrep "iphoneos" |' + 'tail -n 1 | awk \'{print $2}\'', + get_stdout=True)[0] if not sdk: raise Exception( 'No iPhone SDK found. Please install at least one iOS SDK.') else: - print ' -> found %r' % sdk + self.buildozer.debug(' -> found %r' % sdk) self.buildozer.debug('Check Xcode path') - xcode = cmd('xcode-select -print-path')[0] + xcode = cmd('xcode-select -print-path', get_stdout=True)[0] if not xcode: raise Exception('Unable to get xcode path') self.buildozer.debug(' -> found {0}'.format(xcode)) @@ -39,17 +41,101 @@ class TargetIos(Target): cmd('git clean -dxf', cwd=ios_dir) cmd('git pull origin master', cwd=ios_dir) + self.fruitstrap_dir = fruitstrap_dir = join(self.buildozer.platform_dir, + 'fruitstrap') + if not self.buildozer.file_exists(fruitstrap_dir): + cmd('git clone git://github.com/mpurland/fruitstrap.git', + cwd=self.buildozer.platform_dir) + def compile_platform(self): - self.buildozer.cmd('tools/build-all.sh', cwd=self.ios_dir) + state = self.buildozer.state + is_compiled = state.get('ios.platform.compiled', '') + if not is_compiled: + self.buildozer.cmd('tools/build-all.sh', cwd=self.ios_dir) + state['ios.platform.compiled'] = '1' + + if not self.buildozer.file_exists(self.fruitstrap_dir, 'fruitstrap'): + self.buildozer.cmd('make fruitstrap', cwd=self.fruitstrap_dir) def build_package(self): # create the project - app_name = self.buildozer.namify(self.config.get('app', 'title')) + app_name = self.buildozer.namify(self.buildozer.config.get('app', 'title')) - self.app_project_dir = join(self.ios_dir, 'app-{0}'.format(app_name)) - self.buildozer.cmd('tools/create-xcode-project.sh {0} {1}'.format( - app_name, self.buildozer.app_dir), - cwd=self.ios_dir) + self.app_project_dir = join(self.ios_dir, 'app-{0}'.format(app_name.lower())) + if not self.buildozer.file_exists(self.app_project_dir): + self.buildozer.cmd('tools/create-xcode-project.sh {0} {1}'.format( + app_name, self.buildozer.app_dir), + cwd=self.ios_dir) + else: + self.buildozer.cmd('tools/populate-project.sh {0} {1}'.format( + app_name, self.buildozer.app_dir), + cwd=self.ios_dir) + + mode = 'Debug' if self.build_mode == 'debug' else 'Release' + self.buildozer.cmd('xcodebuild -configuration {}'.format(mode), + cwd=self.app_project_dir) + ios_app_dir = 'app-{app_lower}/build/{mode}-iphoneos/{app_lower}.app'.format( + app_lower=app_name.lower(), mode=mode) + self.buildozer.state['ios:latestappdir'] = ios_app_dir + + key = 'ios.codesign.{}'.format(self.build_mode) + ioscodesign = self.buildozer.config.getdefault('app', key, '') + if not ioscodesign: + self.buildozer.error('Cannot create the IPA package without' + ' signature. You must fill the "{}" token.'.format(key)) + 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(( + '/usr/bin/xcrun ' + '-sdk iphoneos PackageApplication {ios_app_dir} ' + '-o {ipa} --sign {ioscodesign} --embed ' + '{ios_app_dir}/embedded.mobileprovision').format( + ioscodesign=ioscodesign, ios_app_dir=ios_app_dir, + mode=mode, ipa=ipa), + cwd=self.ios_dir) + + self.buildozer.info('iOS packaging done!') + self.buildozer.info('IPA {0} available in the bin directory'.format( + basename(ipa))) + self.buildozer.state['ios:latestipa'] = ipa + self.buildozer.state['ios:latestmode'] = self.build_mode + + def cmd_deploy(self, *args): + super(TargetIos, self).cmd_deploy(*args) + self._run_fruitstrap(gdb=False) + + def cmd_run(self, *args): + super(TargetIos, self).cmd_run(*args) + self._run_fruitstrap(gdb=True) + + def _run_fruitstrap(self, gdb=False): + state = self.buildozer.state + if 'ios:latestappdir' not in state: + self.buildozer.error( + 'App not built yet. Run "debug" or "release" first.') + ios_app_dir = state.get('ios:latestappdir') + + if gdb: + gdb_mode = '-d' + self.buildozer.info('Deploy and start the application') + else: + gdb_mode = '' + self.buildozer.info('Deploy the application') + + self.buildozer.cmd('{fruitstrap} {gdb} -b {app_dir}'.format( + fruitstrap=join(self.fruitstrap_dir, 'fruitstrap'), + gdb=gdb_mode, app_dir=ios_app_dir), + cwd=self.ios_dir, show_output=True) + + def check_configuration_tokens(self): + errors = [] + if not self.buildozer.config.getdefault('app', 'ios.codesign.debug'): + errors.append('[app] "ios.codesign.debug" key missing, you must give a certificate name to use.') + super(TargetIos, self).check_configuration_tokens(errors) def get_target(buildozer):