Hi! Since I managed to build/sign/install a Bevy app for iPhone from Linux and I find the documentation online a bit lacking, I thought I would write some words about it. This will be focused on building a Rust app, but the signing/installing steps after "building a .ipa file" step should work for other types of apps too. I'm not an expert in any way, Apple environment is very new to me, some of the stuff I'm not 100% sure how it works, I just want it to be accessible and an incomplete documentation is better than no documentation. And in a way I hope I can help people who are in the same situation as me.
You'll need:
- An iPhone (obviously) (I have an iPhone 12 with iOS 17.4)
- An Apple account with an Apple Developer subscription (no way around that, sadly, it's 99€/year, if you're in a team it's possible to have an organisation set up to pay once for everybody)
- A computer with Linux
- An app coded in Rust
- Not a Mac (hopefully, I did use one for the "Set your phone to developer mode" section but it shouldn't be needed)
I set up my account on the iPhone I bought specifically to test the app I wanted to test. I created a dummy icloud account, provided a fake name, when asked for a phone number provided a fake one and then clicked "I didn't receive anything, try later" (since I have a notification asking me to do it all the time but it works), later when I had to install some stuff I created an itunes account with the icloud account (it's linked to the Apple Play Store apparently). I think I was able to provide a minimum amount of real personal information in the end. Of course I don't encourage you to do any of that if you actually intend to use your iPhone for anything else than testing an app. I just wanted to say it's possible.
Then you need either:
- to ask the person in charge of the dev subscription in your organisation to add your icloud account to the organisation
- to create an account yourself on https://developer.apple.com/ from your computer
- to create an account yourself on the Apple Developer app from your iPhone.
I went with the first option, but just for information since I explored a bit the second option:
- the website will try to nudge you heavily into downloading the app, but there is an option at the bottom like "continue on the website".
- it seems if you started to process with option 2 or 3 but didn't go through (didn't pay) you can't go back to the other one, you still have option 1 available though.
Once you're set-up, you can log in on https://developer.apple.com/, your phone will probably need to be on for 2FA, if everything goes well you should have a page like this (here in French):
Click on Certificates, or go here https://developer.apple.com/account/resources/certificates/list, and you'll have a page like this:
Later I'll refer to the "Certificates", "Devices" and "Profiles" sections of this page (also accessible from the previous one), and the blue "+" button that you might (or not) see on those pages.
You'll need:
- openssl (should be available in your distro's repositories, will not expand)
- Rust's xbuild https://github.com/rust-mobile/xbuild
- (probably optional but good to have) libimobiledevice / idevice https://github.com/libimobiledevice/libimobiledevice
- pymobiledevice3 https://github.com/doronz88/pymobiledevice3 (necessary for iOS 17, for iOS <=16 you can probably stick to libimobiledevice)
- zsign https://github.com/zhlynn/zsign
isign https://github.com/isignpy/isign could also probably be used instead of zsign, but it's not maintained and still using python2 which is a pain to set up. A lot of what I did was from reading their documentation though, especially this page which explains how signing works: https://github.com/isignpy/isign/blob/master/docs/credentials.md , very useful!
Rust's xbuild https://github.com/rust-mobile/xbuild is needed to build for iOS and make a .ipa file (the iPhone app archive file, actually a zip file you can peek into, equivalent to .apk).
Follow the instructions, cargo install xbuild
, then x doctor
to check if you're lacking stuff.
Looking at my history I installed the following packages (using apt
on Linux Mint 21.3, probably some of them are not needed, maybe I already had some you don't): llvm lldb libllvmspirvlib-15-dev liblldb-15-dev libllvm15 llvm-15-dev kotlin
.
x build --help
for usage. x devices
to check if your phone is correctly connected to your computer.
If you don't have /home/yourusername/.cargo/bin
in your PATH
environment variable, you might have to add it (see the zsign installation) or to call it like this ~/.cargo/bin/x build
.
Notes:
- If you want to use xbuild to build for android too, here is more resource on that: https://www.nikl.me/blog/2023/github_workflow_to_publish_android_app/ (you can find a blog post about cargo apk on the same blog, but this tool is unmaintained and android only)
- As we'll see later (see "Build the app" section), xbuild should also be able to sign apps itself, but it doesn't always work, and still requires some preparation, hence this tutorial. If it works for you, you might not need zsign (and maybe not pymobiledevice3 either)
https://github.com/libimobiledevice/libimobiledevice / https://github.com/doronz88/pymobiledevice3
libimobiledevice, or the idevice*
tools, and pymobiledevice3, both allow you to do a lot of things with an iPhone connected to your computer:
- get the UDID of the phone (a unique identifier, we'll need it later)
- get other info about the phone
- install an app on the phone
- launch an app on the phone with logs on the computer
- maybe set your iphone to developer mode? (see section later)
- many other things
In theory, any of them would be enough, but:
- If you have an iPhone with iOS 17, libimobiledevice doesn't support launching and debugging an app with it (among other stuff like taking a screenshot), you'll likely need pymobiledevice3 in that case
- zsign allows to install the app directly after signing it using libimobiledevice
I installed libimobiledevice
using sudo apt-get install libimobiledevice6
. I tried to build it at some point (I don't remember why, probably the app debugging problem), but it failed (I don't remember why either). You can still find many open issues with the app debugging problem for iOS 17, like this one: libimobiledevice/libimobiledevice#1490 so I'm pretty sure building it yourself wouldn't solve the problem.
For pymobiledevice3 you'll need python3/pip3 on your machine, and following the instructions.
idevice
then tab x2 to see all the libimobiledevice commands (idevice_id
, ideviceinstaller
, ...).
python3 -m pymobiledevice3 --help
to see all the commands (and then python3 -m pymobiledevice3 <command> --help
to see usage).
If you do have an iOS <=16, you will probably need to download (on the internet?) and mount a Developer disk image (using ideviceimagemounter
/ pymobiledevice3 mounter
probably) to take screenshots or debug an app. You may need your phone to be in developer mode to do that, see bellow.
I'm not actually sure if this step is necessary, but just in case you may have to download the rust target corresponding to your phone.
You can get your phone's architecture with ideviceinfo | grep Architecture
.
You can list targets with rustup target list | grep ios
, the ones in bold are already installed.
Then if needed rustup target add aarch64-apple-ios
(for example). More info here: https://rust-lang.github.io/rustup/cross-compilation.html
The reason I say I'm not sure it's needed is because my iPhone has an arm64e architecture (compatible arm64, most do probably?), that's what I tell xbuild to use, but it doesn't appear on the list for some reason.
Compile following the instructions.
(optional) I personnally did it in ~/.bin/
a folder I use to compile tools like this, then you can create a link to the zign executable, bring it in ~/.bin/
and add ~/.bin/
to your PATH (export PATH=$PATH:/home/yourusername/.bin
, you can put that in your .bashrc file).
I think this was straightforward for me, sorry if you have problems. ^^'
Simply run x build --arch arm64 --platform ios --format ipa
(adapt the arch
argument if needed).
It should run cargo, compile your project, and if everything goes well, build a myapp.ipa
file (if your project is named myapp) under /pathtomyprojectroot/target/x/debug/ios/arm64
.
Note: there are --pem
and --provisioning-profiles
option for x build
, which theoretically should allow you to sign your app, but I never managed to make it work, probably because the App ID wasn't right, and it doesn't solve the Bevy's asset folder problem. If it works for you, the next steps could be optional (you still need to follow them to have a .pem
and .mobileprovision
files), if so great for you.
There is probably a way to tell xbuild to do it automatically, but you can so it manually.
If you have a graphical UI tool to open archives, just double click on the myapp.ipa
from the previous step. Inside, go to the myapp.app
folder. Drag and drop your project's assets
folder inside it.
There is probably a way to do it from the command line too.
Important: this step should be done before signing the .ipa, otherwise the signature would be invalid.
I'm not 100% sure this is needed, but I think it is, especially if your mobile provisioning profile file (later) is set up for development and not release.
I actually did borrow a MacBook for this step, but I think it might not be needed, at the time I wasn't aware of the existence of pymobiledevice3 or AltServer, and it might not be possible with libimobiledevice (at least on iOS 17).
You can just borrow a MacBook from someone, ask them to download XCode if they don't have it, launch XCode, no need to provide an account ID, download iOS specific stuff, set-up anything, just freshly opened XCode should work.
Then, with XCode still open, connect your phone to the MacBook (warning: it usually only has USB-C, be ready for that), unlock the phone, (accept the connection to the Mac?,) and go to Settings > Privacy and Security and then scroll all the way down. In the "Security" section you should see "Developer mode" and "Lockdown mode". If you have only Lockdown mode, try uplugging the phone and plugging it again.
Activate the Developer Mode and say yes when asked to restart the phone.
I've been told by @SkyLeite it is possible with Altserver on Linux, or AltStore on Windows. I never tested this so you're on your own.
Otherwise I'm not really sure how to do without but maybe python3 -m pymobiledevice3 activation
is about that? Not sure.
This is the step that you might find online as "use Keychain Access to generate a Certificate Signing Request" (for example here: https://github.com/isignpy/isign/blob/master/docs/credentials.md#setting-up-credentials or when you're trying to create a certificate on the Apple Developer website in the next step). We will create a personal certificate to say "this is me, this app comes from me, I joined a certificate to it to prove it" (we'll actually join a "super-certificate" including the personal one, see next step).
Simply run openssl req -sha256 -nodes -newkey rsa:2048 -keyout mycert.key -out mycert.csr
.
You'll be asked a bunch of questions, I'm not sure any of it really matters to be honest, even the challenge password, but don't quote me on that. I don't think you'll need the challenge password after that but best to keep it just in case.
You'll get a .key
file and a .csr
file.
The .key
file (private key) is a secret, you shouldn't upload it anywhere, it will be used by zsign to sign the app.
The .csr
file (certificate signing request) proves that something was signed with your private key.
Note: (optional) If needed, you can create a .pem
file from the two: cat domaine.fr.csr domaine.fr.key > domaine.fr.pem
.
What we need actually to provide in the app is a certificate that proved that you signed it with your key, but also that you're approved by Apple to do so, for that we'll generate a "super" certificate containing both information.
- Go here: https://developer.apple.com/account/resources/certificates/list (Certificates under your dev account)
- Click the "+" button, located on the right of the Certificate title of the page (or go here https://developer.apple.com/account/resources/certificates/add). Note: you might not have it if you're in an organisation, if it's the case ask the person managing the organisation if they can grant you the right, or do the next sub-steps themselves.
- Select "iOS App Development" under "Software".
- You'll be asked to "Upload a Certificate Signing Request", upload the
mycert.csr
file from the previous step (not the.key
file) - Download the
.cer
file that you created, you can give it a name likesupercert.cer
. You'll be able to download it later too.
Note: (optional) you shouldn't need a .p12
file at all (it's equivalent to have mycert.key
and supercert.cer
basically, but the key is protected behind a password, that's what MacOS's Keychain provide). But in case you do, here is how to make one:
- Get a AppleWWDRCAG3.cer file on the page just after clicking "+" in the steps above, in the "Intermediate Certificates" section, named "Worldwide Developer Relations Certificate Authority", or just click here: https://www.apple.com/certificateauthority/AppleWWDRCAG3.cer
- Get a
supercert.pem
file withopenssl x509 -inform der -in supercert.cer -out supercert.pem
, you'll need to provide a password and remember it - Get your p12 file with
openssl pkcs12 -export -clcerts -inkey mycert.key -in supercert.pem -certfile AppleWWDRCAG3.cer -name "Organisation name" -out supercert.p12
- you can extract files again from the .p12 file using isign_export_creds.sh from isign (either after installing isign (not zsign), or copying the scrip directly)
- Get the UDID from your phone using
x devices
,idevice_id
or pymobiledevice3 (not sure how to do it with that last one), it should be like "00000000-0000000000000000" (with 0-9/A-F characters instead of 0s) - Go here: https://developer.apple.com/account/resources/devices/list (Devices under your dev account)
- Click the "+" button (same as previous step, you may not have the rights, you can also go here: https://developer.apple.com/account/resources/devices/add)
- Add the UDID and give the name you want (so you know later which device it is)
- Go here: https://developer.apple.com/account/resources/profiles/list (Devices under your dev account)
- Click the "+" button (same as two previous steps, https://developer.apple.com/account/resources/profiles/add )
- Add certificates and devices from the lists. You can pick several of them, but you need to have at least the certificate you created two steps before (
supercert.cer
) and the device you're using in there. - For the App ID, I think you can use anything, but you may need it later, let's say you picked "myapp"
- Download the file created, you can name it something like
team.mobileprovision
.
Assuming:
- you have zsign in your PATH
- you have
mycert.key
andteam.mobileprovision
files in the root of your project, in which you are - you have a
.ipa
file as explained in the first steps - the App ID is "myapp" (I think that might not matter in the end actually)
Run: zsign -f -k mycert.key -m team.mobileprovision -b "myapp" -o myapp_signed.ipa -i target/x/debug/ios/arm64/myapp.ipa
This will provide you with a signed myapp_signed.ipa
file.
Note:
-f
is optional-z 9
to compress the file (?)-k
can accept themycert.pem
file from above, or thesupercert.p12
file but you'll need to provide the password of the.p12
file with -p
If you have libimobiledevice installed, you can simply use the -i
option of zsign
in the command of the previous step, or you can call it manually after: ideviceinstaller -i myapp_signed.ipa
.
You can probably use python3 -m pymobiledevice3 apps install
too.
If you have an error telling you the mobile provisioning profile isn't valid, make sure that you have the right UDID associated with it, the right certificate, and the right App ID (that last one seem to not matter actually but better safe than sorry).
You should be able to launch the app from the app picker of your phone from that point.
If you have iOS 17.4 or more:
- open 3 terminals
- in the first terminal:
sudo python3 -m pymobiledevice3 remote tunneld
- in the second terminal:
sudo python3 -m pymobiledevice3 lockdown start-tunnel
- in the third terminal:
python3 -m pymobiledevice3 developer dvt launch --stream "myapp"
, you app should launch on your phone and you should see the logs here
You can also pass --env MY_ENVIRONMENT_VARIABLE_NAME "my environment variable value"
to the last command to use a specific environment variable. I don't know of a way to pass arguments to the app, though, but you have at least one way to pass information to it.
If you have between iOS 17.0 and 17.3, then you might need to use rsd instead of lockdown in the second and third terminal, see https://github.com/doronz88/pymobiledevice3?tab=readme-ov-file#working-with-developer-tools-ios--170
If you have iOS 16 or less, then you might be able to do the command in the third terminal if you previously mounted a "Developer disk image", see libimobiledevice's build instruction earlier in this document.