Mobile Development 22 min read

Compilation Optimization and Binary Packaging for QMusic Live Streaming SDK

The team accelerated the QMusic live‑streaming SDK by converting large source modules and external pods into pre‑compiled binaries, tuning Xcode build settings, and automating CI caching, slashing full‑build times from roughly 400 seconds to 40 seconds and packaging duration from over 50 minutes to three minutes.

Tencent Music Tech Team
Tencent Music Tech Team
Tencent Music Tech Team
Compilation Optimization and Binary Packaging for QMusic Live Streaming SDK

Background: The QMusic live streaming SDK was extracted into a pod library and integrated into two independent apps (QQ Music and Fan Live). The live demo project, which imports the SDK via a local pod, suffered from long compilation times as the SDK grew larger.

Key pain points:

Increasing compilation time of the demo project, reducing developer efficiency.

Integrating the SDK source added about 800 s to the host app’s build time.

Complex SDK integration workflow and low CI efficiency caused long verification cycles during testing and gray releases.

The team decided to address these three issues.

Pre‑research

A. Background

The demo project requires re‑running pod install after any file configuration change, which often invalidates the build cache and forces a full recompilation.

To improve compilation speed, two main measures were identified:

Binary integration of large JCE protocol files (2000+ files) instead of exposing source.

Binary integration of external pod libraries used by the live project.

For the second pain point, the SDK can be packaged as a static library and linked to the host without exposing source.

B. Binary方案预研

a. 工程脚手架 + 打包脚本

Typical steps to build a static or dynamic library:

Create an Xcode template project and configure supported architectures.

Run pod install/update to add required pods.

Select the headers to expose.

Build a simulator‑compatible static library (Build Active Architecture Only=NO).

Build a device‑compatible static library.

Merge the generated static libraries.

b. cocoapods‑packager

The official CocoaPods binary packaging plugin can generate a .framework or static library via the command pod package . Only a podspec file is required.

c. cocoapods‑binary

This plugin pre‑compiles all pod libraries in a project to binary caches, allowing near‑zero compilation cost for subsequent builds. It also supports easy switching between source and binary.

Solution Implementation

A. Pain point 1 – Compilation Optimization

Measured on a 2017 iMac (i7, 16 GB) using the iPhone 11 simulator.

a. Compilation option tuning

1. Set Build Active Architecture Only to YES for Debug builds.

2. Disable dSYM generation in Debug.

3. Use non‑recursive Header Search Paths.

4. Turn off Enable Index‑While‑Building .

These settings are already default in Xcode 12, so additional gains were limited.

b. JCE binary integration

JCE files (>2000) were packaged into a static .a library. Automation scripts handle pod integration, header export, and version management.

f = open('subspec.rb', 'w+')
for entry in os.listdir(basepath):
if os.path.isdir(os.path.join(basepath, entry)):
str = f"s.subspec '{entry}' do |ss|\n"
str = str + f"\tss.source_files = \"{basepath}/{entry}/**/*\"\n"
str = str + f"\tss.public_header_files = \"{basepath}/{entry}/**/*.h\"\n"
str = str + "end\n\n"
f.write(str)
f.close()

Version checks ensure the correct jce.podspec is used.

c. Time‑consuming module binary

Using xcpretty and gnomon to profile per‑file compile time revealed that C++/Obj‑C++ mixed files (e.g., KSIMSDK ) dominate the build time.

# Install xcpretty and gnomon
sudo gem install xcpretty
npm install -g gnomon
# Capture compile times
xcodebuild -workspace xxx.xcworkspace -configuration "Debug" -scheme "xxx" -destination "platform=iOS Simulator,id=xxx" | xcpretty | gnomon -i | grep Compiling >>fileTime.txt
# Sort and show top 100
sort -r fileTime.txt | head -n 100 | grep Compiling >> new_fileTime.txt

Result: the most expensive file belonged to KSIMSDK . Converting such modules to static libraries reduced the initial compile time from 400 s to 160 s, then to 140 s after further binary packaging.

d. CocoaPod binary usage

Enabling use_framework! and configuring all_binary! , keep_source_code_for_prebuilt_frameworks! , and enable_bitcode_for_prebuilt_frameworks! allowed automatic binary generation.

sudo gem install cocoapods-binary
sudo gem install cocoapods-packing-cubes

After applying these settings, the initial compile time dropped from 140 s to 90 s.

e. Header index optimization

Using a pre‑compiled header (PCH) and forward declarations reduced header processing overhead. Tools like IWYU (include‑what‑you‑use) helped prune unnecessary includes.

Result: compile time fell from 90 s to 40 s.

B. Pain point 2 – Live Module Binary

The SDK was packaged with cocoapods‑packager using commands such as:

pod package QMLiveCombineModule.podspec \
--exclude-deps \
--spec-sources=xxx,https://github.com/CocoaPods/Specs.git \
--no-mangle \
--force

Key flags:

--exclude-deps : omit dependent symbols for static libraries.

--no-mangle : keep original symbol names.

Podspec configuration (e.g., pod_target_xcconfig ) ensured proper linking flags and architecture exclusions.

'EXCLUDED_ARCHS__EFFECTIVE_PLATFORM_SUFFIX_simulator__NATIVE_ARCH_64_BIT_x86_64' => 'arm64 arm64e armv7 armv7s armv6 armv8',
'EXCLUDED_ARCHS' => '$(inherited) $(EXCLUDED_ARCHS__EFFECTIVE_PLATFORM_SUFFIX_$(EFFECTIVE_PLATFORM_SUFFIX)__NATIVE_ARCH_64_BIT_$(NATIVE_ARCH_64_BIT))',

After static library integration, the QMusic build time decreased from >2000 s to 1000‑1200 s.

C. Pain point 3 – Release Package Speed

By caching build artifacts on a dedicated CI pipeline (Blue Shield), avoiding xcodebuild clean , using build instead of archive , and directing derivedDataPath to a fixed location, the full packaging time dropped from >50 min to 3 min.

Additional steps included creating an .ipa by placing the built .app into a Payload folder and zipping it.

Overall Summary

Through modularization, binary packaging, header index optimization, and CI automation, the live streaming SDK’s initial full‑build time was reduced from nearly 400 s to 40 s, and incremental builds now take only seconds. The binary solutions (engineered via Xcode scaffolding, cocoapods‑packager , and cocoapods‑binary ) are applicable to various scenarios, from single pod packaging to whole‑project binary conversion.

iOSbuild optimizationCocoaPodsCIbinary packagingPodSpecstatic library
Tencent Music Tech Team
Written by

Tencent Music Tech Team

Public account of Tencent Music's development team, focusing on technology sharing and communication.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.