DECODE wiki
This page is to list all the small pieces of knowledge we use, to have them as a refresher in a single place. As it's very likely they are used infrequently enough to be forgotten, this is a good reminder on how to use them.
Export APNS certificate and keys
After generating the APNS sandbox/prod APNS certificate on the Developer Portal, download and import the .cer file to Keychain by double-clicking it. After that, open Keychain Access, navigate to the Certificates section and find the appropriate Certificate along with the private key used to generate it. Expand the entry to show both the Certificate and the associated key, select them both and right-click to export. Export as .p12 file and choose destination (and export password).
After that, open Terminal and navigate to that destination. To covert the .p12 file to .pem files that are usually required, enter the following commands:
- To export the certitifcate only:
openssl pkcs12 -in input.p12 -out output.crt.pem -clcerts -nokeys
- To export the Key only:
openssl pkcs12 -in input.p12 -out output.key.pem -nocerts -nodes
- To export both Certificate and Key:
openssl pkcs12 -in input.p12 -out output.pem -nodes
This works both for APNS and VoIP Certificates.
Running those commands might give you an error, if so try using openSSL 1.1.1w as v3 may have incompatibilities with the .p12 contents.
Initialize and use git-lfs in the repository (that already has it enabled)
Some of our projects use git-lfs to handle the storage of large files outside of the repository. The first step is to install git-lfs if it is not installed, e.g. using Homebrew.
After that, go to the project folder in terminal, initialize and pull the LFS files using
git lfs install
git lfs pull
Use the git submodules in the current project
Some of the our projects depend od git submodules for dependencies. After inital cloning, you are likely to need installing submodule dependencies by running
git submodule init
git submodule update
you can update a particular dependency only by invoking
git submodule update <dependency_name>
Re-install or update CocoaPods dependencies
Most of our projects that use Cocoapods as dependency manager have all the dependencies checked into the Git repository along with the project and are therefore fully buildable. If you for any reason need to re-install dependencies you can use
pod install
command that will install the explicit versions defined the Package.lock file. This will ensure you're using the exact version that is used in the project.
If you need/want to update the dependencies, use
pod repo update
pod update
to first update all the Cocoapods repo sources, and then all the dependencies (if they are not version-locked in the Podfile). However, it may be wiser to make more granular update - per-dependency by calling
pod update <dependency_name>
which will update that particular dependency only.
Re-signing the application
On occassion it is required that we either re-sign the created .ipa file with another bundle identifier, Apple Developer Identity or just change some metadata (e.g. app name, bundle version or build number).
.ipa file is basically just a .zip archive so it is easy to edit, but as it is signed changing anything within it will break it, unless it is re-signed.
Re-signing can be performed completely manually by utilizing the codesign
command, along with creating the entitlements (.xcent) file. As that is a slightly more hands-on process, it will not be described in detail here. However, if you choose to do so, please note the re-signing process must be performed from leaf dependencies upwards. If the app contains any frameworks, they must be signed first using
codesign -f -s "<Signing Identity Name>" -vv <ApplicationName>.app/Frameworks/*
and then the main app, but this time including generated entitlements file as well:
codesign -f -s "<Signing Identity Name>" --entitlements <entitlements_name>.xcent -vv <ApplicationName>.app/${InternalName}
and then compress the results back the .ipa file.
Howeve, it is highly suggested to use Fastlane's sigh tool to perform the re-signing process. Under the hood, it utilizes exact steps from above, but in a more user-friendly manner. The syntax is:
fastlane sigh resign ./<name>.ipa -i "<Apple/iPhone> Distribution:
<Company> (<company id>)" --short_version <version> --bundle_version <build_number> -p
./<name>.mobileprovision -d "<New application name>"
Fastlane is smart enough to determine the signing identity if it is the only one in the Keychain and the provisioning profile if it is the only one in the folder, but if you want/need to control all the paramterers, they are as follows:
- -i: Signing identity name, as can be determined from Keychain Access
- --short_version: Application version to set/overried, e.g. 1.15.0
- --bundle_version: Bundle version of the application to set/override, e.g. 41
- -p: Name of the Provisioning profile to be used
- -d: Display name of the Application (if you want to change it)
Add build time to Xcode
It might be useful/interesting to track how long did a build take. To show it in Xcode, execute this commant in the Terminal.
defaults write com.apple.dt.Xcode ShowBuildOperationDuration YES
Crash symbolication
Every app should have a reliable crash reporting tool, such as Firebase Crashlytics or Shake, with a user-friendly dashboard that allows you to easily identify and address the latest bugs. These tools symbolicate crash logs and provide insight into the specific functions and lines of code where the crash occurred. In the event that the tool fails to symbolicate the crash, you can still symbolicate it manually.
To symbolicate crashes manually follow these steps:
Obtain the dSYM file for the build either from AppStore or from app archive. Make sure you are using the right dSYM, because every time you build your app a different dSYM file is generated.
To check the UUID of your build:
xcrun dwarfdump --uuid ./Symbolication.app/Symbolication
UUID: EE386945-877C-3F62-8C63-38CE7E1849B3 (arm64) ./Symbolication.app/SymbolicationIn your crash file, scroll down to
Binary images
section and you will see something like this:
0x10442c000 - 0x1023c3fff Symbolication arm64 <ee386945877c3f628c6338ce7e1849b3>
.If UUIDs from previous two steps match, you are looking at the right build.
Find the location of
symbolicatecrash
tool:
find /Applications -name symbolicatecrash
- Set the
DEVELOPER_DIR
environment variable:
DEVELOPER_DIR="/Applications/Xcode.app/Contents/Developer"
- Symbolicate to an output file, e.g.: "Symbolicated.crash"
/Applications/Xcode.app/Contents/SharedFrameworks/DVTFoundation.framework/Versions/A/Resources/symbolicatecrash Crash.crash Symbolication.app.dSYM > Symbolicated.crash
You can also use atos
command (short for "addresses to symbols") to symbolicate specific lines.
Crash log could contain the following info about the crash:
Thread 0 Crashed:
0 libsystem_kernel.dylib 0x1b73f6964 0x1b73ef000 + 31076
1 Symbolication 0x10456b710 0x10442c000 + 1308432
2 CoreFoundation 0x1804d1c10 0x1803b8000 + 1154064
3 libc++abi.dylib 0x198bccf58 0x198bba000 + 77656
Take the following line:
1 Symbolication 0x10456b710 0x10442c000 + 1308432
0x10456b710
- is the memory address we want to symbolicate
0x10442c000
- is the application's load address
Scroll down to Binary images
section to check for application's architecture:
0x10442c000 - 0x1023c3fff Symbolication arm64 <ee386945877c3f628c6338ce7e1849b3>
Execute atos
command:
atos -arch arm64 -o Symbolication.app.dSYM/Contents/Resources/DWARF/CommPortal -l 0x10442c000 0x10456b710
(Re)install iOS simulators
If for any reason iOS simulators are missing as run destinations in Xcode, you can re-create them by hand. However that is a tedious process and there is a better way. Using fastlane's snapshot tool you can reinstall all available simulators.
Once fastlane is installed in any manner, run
fastlane snapshot reset_simulators
or if using Gemfile
bundle exec fastlane snapshot reset_simulators