Debug & Testing
How to verify your app works correctly after applying Shield iOS protections.
Understanding the Build Flow
| Action | Mode | Shield runs? | Purpose |
|---|---|---|---|
Play (Cmd+R) | Debug | Only with Debug Build Integration | Day-to-day development |
Archive (Product > Archive) | Release | Yes (post-archive) | Distribution builds |
By default, Shield only runs on Archive/Release builds. This is by design so obfuscation doesn't slow down your debug cycle. If you want to test protections during debug, see Debug Build Integration.
Testing a Protected Build
Option 1: Device via Xcode (Recommended)
The simplest way to test a protected build on a real device:
- Archive your app (
Product > Archive) - Shield runs automatically (post-archive action)
- In Organizer, click Distribute App
- Select Development distribution
- Install on your device and test
Option 2: Simulator via CLI
To test a protected build in the simulator:
# 1. Archive
xcodebuild archive \
-project MyApp.xcodeproj \
-scheme MyApp \
-archivePath build/MyApp.xcarchive \
-destination "generic/platform=iOS Simulator"
# 2. Protect
shield-ios protect build/MyApp.xcarchive \
-o build/MyApp.xcarchive \
--config shield-ios.json \
--no-sign
# 3. Export for simulator
xcodebuild -exportArchive \
-archivePath build/MyApp.xcarchive \
-exportOptionsPlist ExportOptions.plist \
-exportPath build/output
# 4. Install and launch in simulator
xcrun simctl install booted build/output/MyApp.app
xcrun simctl launch booted com.example.MyApp# 1. Archive
xcodebuild archive \
-project MyApp.xcodeproj \
-scheme MyApp \
-archivePath build/MyApp.xcarchive \
-destination "generic/platform=iOS Simulator"
# 2. Protect
shield-ios protect build/MyApp.xcarchive \
-o build/MyApp.xcarchive \
--config shield-ios.json \
--no-sign
# 3. Export for simulator
xcodebuild -exportArchive \
-archivePath build/MyApp.xcarchive \
-exportOptionsPlist ExportOptions.plist \
-exportPath build/output
# 4. Install and launch in simulator
xcrun simctl install booted build/output/MyApp.app
xcrun simctl launch booted com.example.MyAppOption 3: Protect an IPA Directly
If you already have an IPA:
# Protect
shield-ios protect MyApp.ipa --config shield-ios.json
# Install on device via Xcode
# Drag MyApp_protected.ipa onto your device in Xcode > Devices# Protect
shield-ios protect MyApp.ipa --config shield-ios.json
# Install on device via Xcode
# Drag MyApp_protected.ipa onto your device in Xcode > DevicesWhat to Test
After applying protections, verify:
- App launches without crashes
- Core functionality works (login, navigation, data loading)
- Network requests succeed (API calls, push notifications)
- Persistence works (CoreData, UserDefaults, Keychain)
- UI performance is acceptable (animations, scrolling)
Protections That Can Affect Behavior
Most protections are transparent, but some have observable effects:
| Protection | What to watch for |
|---|---|
anti_debug | App exits when attached to debugger (expected behavior) |
anti_jailbreak | App exits on jailbroken devices (expected behavior) |
control_flow: "aggressive" | Slight performance overhead on hot paths |
resource_encryption | First launch may be slightly slower (decryption) |
Debugging a Protected Build
Since anti_debug prevents debugger attachment, you can't use Xcode's debugger on a protected build with that protection enabled. To debug issues:
- Temporarily disable
anti_debuginshield-ios.json:
{
"protections": {
"anti_debug": false,
"string_encryption": true,
"control_flow": "medium"
}
}{
"protections": {
"anti_debug": false,
"string_encryption": true,
"control_flow": "medium"
}
}- Re-archive, protect, and test
- Once verified, re-enable
anti_debugfor the production build
Debug Build Integration
For a faster workflow, use Debug Build Integration to protect your app automatically on every Cmd+R. This avoids the archive/distribute cycle entirely during development.
Testing Protection Levels
Start with minimal protections and increase gradually:
# Step 1: Test with minimal protections
shield-ios protect MyApp.ipa --config shield-ios-minimal.json
# Step 2: Test with production protections
shield-ios protect MyApp.ipa --config shield-ios.json
# Step 3: Test with maximum protections
shield-ios protect MyApp.ipa --config shield-ios-max.json# Step 1: Test with minimal protections
shield-ios protect MyApp.ipa --config shield-ios-minimal.json
# Step 2: Test with production protections
shield-ios protect MyApp.ipa --config shield-ios.json
# Step 3: Test with maximum protections
shield-ios protect MyApp.ipa --config shield-ios-max.jsonCI/CD Testing
In your CI pipeline, add a smoke test after protection.
GitHub Actions
- name: Archive
run: |
xcodebuild archive \
-scheme MyApp \
-archivePath build/MyApp.xcarchive
- name: Protect
run: |
shield-ios protect build/MyApp.xcarchive \
-o build/MyApp.xcarchive \
--config shield-ios.json \
--no-sign
- name: Export IPA
run: |
xcodebuild -exportArchive \
-archivePath build/MyApp.xcarchive \
-exportOptionsPlist ExportOptions.plist \
-exportPath build/output
- name: Verify IPA exists and is valid
run: |
test -f build/output/MyApp.ipa
unzip -t build/output/MyApp.ipa- name: Archive
run: |
xcodebuild archive \
-scheme MyApp \
-archivePath build/MyApp.xcarchive
- name: Protect
run: |
shield-ios protect build/MyApp.xcarchive \
-o build/MyApp.xcarchive \
--config shield-ios.json \
--no-sign
- name: Export IPA
run: |
xcodebuild -exportArchive \
-archivePath build/MyApp.xcarchive \
-exportOptionsPlist ExportOptions.plist \
-exportPath build/output
- name: Verify IPA exists and is valid
run: |
test -f build/output/MyApp.ipa
unzip -t build/output/MyApp.ipaFastlane
lane :test_protected do
build_app(
scheme: "MyApp",
archive_path: "build/MyApp.xcarchive",
skip_package_ipa: true
)
shield_ios(
archive_path: "build/MyApp.xcarchive",
config: "shield-ios.json"
)
build_app(
archive_path: "build/MyApp.xcarchive",
skip_build_archive: true,
export_method: "development"
)
# Install on a connected device for manual testing
install_on_device(skip_wifi: true)
endlane :test_protected do
build_app(
scheme: "MyApp",
archive_path: "build/MyApp.xcarchive",
skip_package_ipa: true
)
shield_ios(
archive_path: "build/MyApp.xcarchive",
config: "shield-ios.json"
)
build_app(
archive_path: "build/MyApp.xcarchive",
skip_build_archive: true,
export_method: "development"
)
# Install on a connected device for manual testing
install_on_device(skip_wifi: true)
endNext Steps
Xcode Integration
Automatic protection on Archive and Debug builds
Configuration Reference
Full protection options
CI/CD Integration
GitHub Actions, GitLab CI, and more
Troubleshooting
Common issues and solutions