🍏 Improves iOS support

Updates & fixes support for iOS target, covers the following:
- Build integration test
- Updates to new kivy-ios structure
- Bumps to ios-deploy 1.10.0 (`make` replaced by `xcodebuild`)
- Makes it possible to toggle code signing (now disabled by default)

Note this is the first iteration of a longer serie.
Subsequent pull requests will try to improve the following:
- code signing process (toggle not fully integrated)
- actual deployment (not yet tested)
- unit tests (mainly `buildozer/targets/ios.py`)
- other forms of technical debt
This commit is contained in:
Andre Miras 2020-06-19 11:32:57 -07:00
parent af577b6138
commit 020a5504f3
5 changed files with 64 additions and 26 deletions

View file

@ -17,7 +17,7 @@ jobs:
- name: Setup environment - name: Setup environment
run: | run: |
pip install -e . pip install -e .
pip install Cython==0.29.19 pip install Cython
- run: buildozer --help - run: buildozer --help
- run: buildozer init - run: buildozer init
- name: SDK, NDK and p4a download - name: SDK, NDK and p4a download

24
.github/workflows/ios.yml vendored Normal file
View file

@ -0,0 +1,24 @@
on: [push, pull_request]
name: iOS
jobs:
Integration:
runs-on: macOS-latest
steps:
- name: Setup python
uses: actions/setup-python@v2
with:
python-version: 3.8
- uses: actions/checkout@v2
- name: Setup environment
run: |
pip install -e .
pip install Cython cookiecutter pbxproj
- run: buildozer --help
- run: buildozer init
- name: Install dependencies
run: |
brew install autoconf automake libtool pkg-config
- name: buildozer ios debug
run: |
touch main.py
buildozer ios debug

View file

@ -1,8 +1,9 @@
Buildozer Buildozer
========= =========
[![Build](https://github.com/kivy/buildozer/workflows/Tests/badge.svg)](https://github.com/kivy/buildozer/actions?query=workflow%3ATests) [![Tests](https://github.com/kivy/buildozer/workflows/Tests/badge.svg)](https://github.com/kivy/buildozer/actions?query=workflow%3ATests)
[![Build](https://github.com/kivy/buildozer/workflows/Android/badge.svg)](https://github.com/kivy/buildozer/actions?query=workflow%3AAndroid) [![Android](https://github.com/kivy/buildozer/workflows/Android/badge.svg)](https://github.com/kivy/buildozer/actions?query=workflow%3AAndroid)
[![iOS](https://github.com/kivy/buildozer/workflows/iOS/badge.svg)](https://github.com/kivy/buildozer/actions?query=workflow%3AiOS)
[![Coverage Status](https://coveralls.io/repos/github/kivy/buildozer/badge.svg)](https://coveralls.io/github/kivy/buildozer) [![Coverage Status](https://coveralls.io/repos/github/kivy/buildozer/badge.svg)](https://coveralls.io/github/kivy/buildozer)
[![Backers on Open Collective](https://opencollective.com/kivy/backers/badge.svg)](#backers) [![Backers on Open Collective](https://opencollective.com/kivy/backers/badge.svg)](#backers)
[![Sponsors on Open Collective](https://opencollective.com/kivy/sponsors/badge.svg)](#sponsors) [![Sponsors on Open Collective](https://opencollective.com/kivy/sponsors/badge.svg)](#sponsors)

View file

@ -22,7 +22,7 @@ source.include_exts = py,png,jpg,kv,atlas
#source.exclude_exts = spec #source.exclude_exts = spec
# (list) List of directory to exclude (let empty to not exclude anything) # (list) List of directory to exclude (let empty to not exclude anything)
#source.exclude_dirs = tests, bin #source.exclude_dirs = tests, bin, venv
# (list) List of exclusions using pattern matching # (list) List of exclusions using pattern matching
#source.exclude_patterns = license,images/*/*.jpg #source.exclude_patterns = license,images/*/*.jpg
@ -263,7 +263,10 @@ ios.kivy_ios_branch = master
#ios.ios_deploy_dir = ../ios_deploy #ios.ios_deploy_dir = ../ios_deploy
# Or specify URL and branch # Or specify URL and branch
ios.ios_deploy_url = https://github.com/phonegap/ios-deploy ios.ios_deploy_url = https://github.com/phonegap/ios-deploy
ios.ios_deploy_branch = 1.7.0 ios.ios_deploy_branch = 1.10.0
# (bool) Whether or not to sign the code
ios.codesign.allowed = false
# (str) Name of the certificate to use for signing the debug version # (str) Name of the certificate to use for signing the debug version
# Get a list of available identities: buildozer ios list_identities # Get a list of available identities: buildozer ios list_identities

View file

@ -66,6 +66,9 @@ class TargetIos(Target):
def check_requirements(self): def check_requirements(self):
checkbin = self.buildozer.checkbin checkbin = self.buildozer.checkbin
cmd = self.buildozer.cmd cmd = self.buildozer.cmd
executable = sys.executable or 'python'
self._toolchain_cmd = f"{executable} toolchain.py "
self._xcodebuild_cmd = "xcodebuild "
checkbin('Xcode xcodebuild', 'xcodebuild') checkbin('Xcode xcodebuild', 'xcodebuild')
checkbin('Xcode xcode-select', 'xcode-select') checkbin('Xcode xcode-select', 'xcode-select')
@ -99,10 +102,21 @@ class TargetIos(Target):
branch='1.7.0', branch='1.7.0',
owner='phonegap') owner='phonegap')
def toolchain(self, cmd, **kwargs):
kwargs.setdefault('cwd', self.ios_dir)
return self.buildozer.cmd(self._toolchain_cmd + cmd, **kwargs)
def xcodebuild(self, cmd='', **kwargs):
return self.buildozer.cmd(self._xcodebuild_cmd + cmd, **kwargs)
@property
def code_signing_allowed(self):
allowed = self.buildozer.config.getboolean("app", "ios.codesign.allowed")
allowed = "YES" if allowed else "NO"
return f"CODE_SIGNING_ALLOWED={allowed}"
def get_available_packages(self): def get_available_packages(self):
available_modules = self.buildozer.cmd( available_modules = self.toolchain("recipes --compact", get_stdout=True)[0]
'./toolchain.py recipes --compact',
cwd=self.ios_dir, get_stdout=True)[0]
return available_modules.splitlines()[0].split() return available_modules.splitlines()[0].split()
def compile_platform(self): def compile_platform(self):
@ -139,11 +153,10 @@ class TargetIos(Target):
return return
modules_str = ' '.join(ios_requirements) modules_str = ' '.join(ios_requirements)
self.buildozer.cmd('./toolchain.py build {}'.format(modules_str), self.toolchain(f"build {modules_str}")
cwd=self.ios_dir)
if not self.buildozer.file_exists(self.ios_deploy_dir, 'ios-deploy'): if not self.buildozer.file_exists(self.ios_deploy_dir, 'ios-deploy'):
self.buildozer.cmd('make ios-deploy', cwd=self.ios_deploy_dir) self.xcodebuild(cwd=self.ios_deploy_dir)
self.buildozer.state['ios.requirements'] = ios_requirements self.buildozer.state['ios.requirements'] = ios_requirements
self.buildozer.state.sync() self.buildozer.state.sync()
@ -170,12 +183,10 @@ class TargetIos(Target):
self.app_project_dir = join(self.ios_dir, '{0}-ios'.format(app_name.lower())) self.app_project_dir = join(self.ios_dir, '{0}-ios'.format(app_name.lower()))
if not self.buildozer.file_exists(self.app_project_dir): if not self.buildozer.file_exists(self.app_project_dir):
create_cmd = './toolchain.py create {0}{1} {2}'.format(frameworks_cmd, app_name, cmd = f"create {frameworks_cmd}{app_name} {self.buildozer.app_dir}"
self.buildozer.app_dir)
self.buildozer.cmd(create_cmd, cwd=self.ios_dir)
else: else:
update_cmd = './toolchain.py update {0}{1}-ios'.format(frameworks_cmd, app_name) cmd = f"update {frameworks_cmd}{app_name}-ios"
self.buildozer.cmd(update_cmd, cwd=self.ios_dir) self.toolchain(cmd)
# fix the plist # fix the plist
plist_fn = '{}-Info.plist'.format(app_name.lower()) plist_fn = '{}-Info.plist'.format(app_name.lower())
@ -194,9 +205,10 @@ class TargetIos(Target):
# ok, write the modified plist. # ok, write the modified plist.
plistlib.writePlist(plist, plist_rfn) plistlib.writePlist(plist, plist_rfn)
mode = 'Debug' if self.build_mode == 'debug' else 'Release' mode = self.build_mode.capitalize()
self.buildozer.cmd('xcodebuild -configuration {} ENABLE_BITCODE=NO clean build'.format(mode), self.xcodebuild(
cwd=self.app_project_dir) f"-configuration {mode} ENABLE_BITCODE=NO {self.code_signing_allowed} clean build",
cwd=self.app_project_dir)
ios_app_dir = '{app_lower}-ios/build/{mode}-iphoneos/{app_lower}.app'.format( ios_app_dir = '{app_lower}-ios/build/{mode}-iphoneos/{app_lower}.app'.format(
app_lower=app_name.lower(), mode=mode) app_lower=app_name.lower(), mode=mode)
self.buildozer.state['ios:latestappdir'] = ios_app_dir self.buildozer.state['ios:latestappdir'] = ios_app_dir
@ -221,8 +233,7 @@ class TargetIos(Target):
self.buildozer.rmdir(intermediate_dir) self.buildozer.rmdir(intermediate_dir)
self.buildozer.info('Creating archive...') self.buildozer.info('Creating archive...')
self.buildozer.cmd(( self.xcodebuild((
'/usr/bin/xcodebuild'
' -alltargets' ' -alltargets'
' -configuration {mode}' ' -configuration {mode}'
' -scheme {scheme}' ' -scheme {scheme}'
@ -233,8 +244,7 @@ class TargetIos(Target):
cwd=build_dir) cwd=build_dir)
self.buildozer.info('Creating IPA...') self.buildozer.info('Creating IPA...')
self.buildozer.cmd(( self.xcodebuild((
'/usr/bin/xcodebuild'
' -exportArchive' ' -exportArchive'
' -exportFormat IPA' ' -exportFormat IPA'
' -archivePath "{xcarchive}"' ' -archivePath "{xcarchive}"'
@ -301,13 +311,13 @@ class TargetIos(Target):
self.buildozer.error('Icon {} does not exists'.format(icon_fn)) self.buildozer.error('Icon {} does not exists'.format(icon_fn))
return return
self.buildozer.cmd('./toolchain.py icon {} {}'.format( self.toolchain(f"icon {self.app_project_dir} {icon_fn}")
self.app_project_dir, icon_fn),
cwd=self.ios_dir)
def check_configuration_tokens(self): def check_configuration_tokens(self):
errors = [] errors = []
config = self.buildozer.config config = self.buildozer.config
if not config.getboolean('app', 'ios.codesign.allowed'):
return
identity_debug = config.getdefault('app', 'ios.codesign.debug', '') identity_debug = config.getdefault('app', 'ios.codesign.debug', '')
identity_release = config.getdefault('app', 'ios.codesign.release', identity_release = config.getdefault('app', 'ios.codesign.release',
identity_debug) identity_debug)