2021-02-05 17:12:51 +00:00
{ stdenv , lib , composeXcodeWrapper }:
2020-04-24 23:36:52 +00:00
{ name
, src
, sdkVersion ? " 1 3 . 1 "
, target ? null
, configuration ? null
, scheme ? null
, sdk ? null
, xcodeFlags ? " "
, release ? false
, certificateFile ? null
, certificatePassword ? null
, provisioningProfile ? null
, codeSignIdentity ? null
, signMethod ? null
, generateIPA ? false
, generateXCArchive ? false
, enableWirelessDistribution ? false
, installURL ? null
, bundleId ? null
, appVersion ? null
, . . .
} @ args :
assert release -> certificateFile != null && certificatePassword != null && provisioningProfile != null && signMethod != null && codeSignIdentity != null ;
assert enableWirelessDistribution -> installURL != null && bundleId != null && appVersion != null ;
let
# Set some default values here
_target = if target == null then name else target ;
_configuration = if configuration == null
then
if release then " R e l e a s e " else " D e b u g "
else configuration ;
_sdk = if sdk == null
then
if release then " i p h o n e o s " + sdkVersion else " i p h o n e s i m u l a t o r " + sdkVersion
else sdk ;
# The following is to prevent repetition
deleteKeychain = ''
security default-keychain - s login . keychain
security delete-keychain $ keychainName
'' ;
xcodewrapperFormalArgs = builtins . functionArgs composeXcodeWrapper ;
xcodewrapperArgs = builtins . intersectAttrs xcodewrapperFormalArgs args ;
xcodewrapper = composeXcodeWrapper xcodewrapperArgs ;
extraArgs = removeAttrs args ( [ " n a m e " " s c h e m e " " x c o d e F l a g s " " r e l e a s e " " c e r t i f i c a t e F i l e " " c e r t i f i c a t e P a s s w o r d " " p r o v i s i o n i n g P r o f i l e " " s i g n M e t h o d " " g e n e r a t e I P A " " g e n e r a t e X C A r c h i v e " " e n a b l e W i r e l e s s D i s t r i b u t i o n " " i n s t a l l U R L " " b u n d l e I d " " v e r s i o n " ] ++ builtins . attrNames xcodewrapperFormalArgs ) ;
in
stdenv . mkDerivation ( {
2021-02-05 17:12:51 +00:00
name = lib . replaceChars [ " " ] [ " " ] name ; # iOS app names can contain spaces, but in the Nix store this is not allowed
2020-04-24 23:36:52 +00:00
buildPhase = ''
# Be sure that the Xcode wrapper has priority over everything else.
# When using buildInputs this does not seem to be the case.
export PATH = $ { xcodewrapper } /bin : $ PATH
2021-02-05 17:12:51 +00:00
$ { lib . optionalString release ''
2020-04-24 23:36:52 +00:00
export HOME = /Users / $ ( whoami )
keychainName = " $ ( b a s e n a m e $ o u t ) "
# Create a keychain
security create-keychain - p " " $ keychainName
security default-keychain - s $ keychainName
security unlock-keychain - p " " $ keychainName
# Import the certificate into the keychain
2021-02-05 17:12:51 +00:00
security import $ { certificateFile } - k $ keychainName - P " ${ certificatePassword } " - A
2020-04-24 23:36:52 +00:00
# Grant the codesign utility permissions to read from the keychain
security set-key-partition-list - S apple-tool:,apple: - s - k " " $ keychainName
# Determine provisioning ID
PROVISIONING_PROFILE = $ ( grep UUID - A1 - a $ { provisioningProfile } | grep - o " [ - A - Z a - z 0 - 9 ] \{ 3 6 \} " )
if [ ! - f " $ H O M E / L i b r a r y / M o b i l e D e v i c e / P r o v i s i o n i n g P r o f i l e s / $ P R O V I S I O N I N G _ P R O F I L E . m o b i l e p r o v i s i o n " ]
then
# Copy provisioning profile into the home directory
mkdir - p " $ H O M E / L i b r a r y / M o b i l e D e v i c e / P r o v i s i o n i n g P r o f i l e s "
cp $ { provisioningProfile } " $ H O M E / L i b r a r y / M o b i l e D e v i c e / P r o v i s i o n i n g P r o f i l e s / $ P R O V I S I O N I N G _ P R O F I L E . m o b i l e p r o v i s i o n "
fi
# Check whether the identity can be found
security find-identity - p codesigning $ keychainName
'' }
# Do the building
export LD = /usr/bin/clang # To avoid problem with -isysroot parameter that is unrecognized by the stock ld. Comparison with an impure build shows that it uses clang instead. Ugly, but it works
2021-02-05 17:12:51 +00:00
xcodebuild - target $ { _target } - configuration $ { _configuration } $ { lib . optionalString ( scheme != null ) " - s c h e m e ${ scheme } " } - sdk $ { _sdk } TARGETED_DEVICE_FAMILY = " 1 , 2 " ONLY_ACTIVE_ARCH = NO CONFIGURATION_TEMP_DIR = $ TMPDIR CONFIGURATION_BUILD_DIR = $ out $ { if generateIPA || generateXCArchive then " - a r c h i v e P a t h \" ${ name } . x c a r c h i v e \" a r c h i v e " else " " } $ { if release then '' P R O V I S I O N I N G _ P R O F I L E = $P R O V I S I O N I N G _ P R O F I L E O T H E R _ C O D E _ S I G N _ F L A G S = " - - k e y c h a i n $H O M E / L i b r a r y / K e y c h a i n s / $k e y c h a i n N a m e - d b " '' else " " } $ { xcodeFlags }
2020-04-24 23:36:52 +00:00
2021-02-05 17:12:51 +00:00
$ { lib . optionalString release ''
$ { lib . optionalString generateIPA ''
2020-04-24 23:36:52 +00:00
# Create export plist file
cat > " ${ name } . p l i s t " < < EOF
< ? xml version = " 1 . 0 " encoding = " U T F - 8 " ? >
< ! DOCTYPE plist PUBLIC " - / / A p p l e / / D T D P L I S T 1 . 0 / / E N " " h t t p : / / w w w . a p p l e . c o m / D T D s / P r o p e r t y L i s t - 1 . 0 . d t d " >
< plist version = " 1 . 0 " >
<dict>
<key> signingCertificate < /key >
<string> $ { codeSignIdentity } < /string >
<key> provisioningProfiles < /key >
<dict>
<key> $ { bundleId } < /key >
<string> $ PROVISIONING_PROFILE < /string >
< /dict >
<key> signingStyle < /key >
<string> manual < /string >
<key> method < /key >
<string> $ { signMethod } < /string >
2021-02-05 17:12:51 +00:00
$ { lib . optionalString ( signMethod == " e n t e r p r i s e " || signMethod == " a d - h o c " ) ''
2020-04-24 23:36:52 +00:00
<key> compileBitcode < /key >
< false / >
'' }
< /dict >
< /plist >
EOF
# Produce an IPA file
xcodebuild - exportArchive - archivePath " ${ name } . x c a r c h i v e " - exportOptionsPlist " ${ name } . p l i s t " - exportPath $ out
# Add IPA to Hydra build products
mkdir - p $ out/nix-support
echo " f i l e b i n a r y - d i s t \" $ ( e c h o $ o u t / * . i p a ) \" " > $ out/nix-support/hydra-build-products
2021-02-05 17:12:51 +00:00
$ { lib . optionalString enableWirelessDistribution ''
2020-04-24 23:36:52 +00:00
# Add another hacky build product that enables wireless adhoc installations
appname = " $ ( b a s e n a m e " $ ( echo $ out /* . i p a ) " . i p a ) "
sed - e " s | @ I N S T A L L _ U R L @ | ${ installURL } ? b u n d l e I d = ${ bundleId } \& a m p ; v e r s i o n = ${ appVersion } \& a m p ; t i t l e = $ a p p n a m e | " $ { ./install.html.template } > $ out / '' ${ appname } . h t m l
echo " d o c i n s t a l l \" $ o u t / ' ' ${ appname } . h t m l \" " > > $ out/nix-support/hydra-build-products
'' }
'' }
2021-02-05 17:12:51 +00:00
$ { lib . optionalString generateXCArchive ''
2020-04-24 23:36:52 +00:00
mkdir - p $ out
mv " ${ name } . x c a r c h i v e " $ out
'' }
# Delete our temp keychain
$ { deleteKeychain }
'' }
'' ;
2021-02-05 17:12:51 +00:00
failureHook = lib . optionalString release deleteKeychain ;
2020-04-24 23:36:52 +00:00
installPhase = " t r u e " ;
} // extraArgs )