/

Debug & Testing

How to verify your app works correctly after applying Shield iOS protections.


Understanding the Build Flow

ActionModeShield runs?Purpose
Play (Cmd+R)DebugOnly with Debug Build IntegrationDay-to-day development
Archive (Product > Archive)ReleaseYes (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

The simplest way to test a protected build on a real device:

  1. Archive your app (Product > Archive)
  2. Shield runs automatically (post-archive action)
  3. In Organizer, click Distribute App
  4. Select Development distribution
  5. Install on your device and test

Option 2: Simulator via CLI

To test a protected build in the simulator:

Bash
# 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

Option 3: Protect an IPA Directly

If you already have an IPA:

Bash
# 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

What 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:

ProtectionWhat to watch for
anti_debugApp exits when attached to debugger (expected behavior)
anti_jailbreakApp exits on jailbroken devices (expected behavior)
control_flow: "aggressive"Slight performance overhead on hot paths
resource_encryptionFirst 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:

  1. Temporarily disable anti_debug in shield-ios.json:
JSON
{
  "protections": {
    "anti_debug": false,
    "string_encryption": true,
    "control_flow": "medium"
  }
}
  1. Re-archive, protect, and test
  2. Once verified, re-enable anti_debug for 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:

Bash
# 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

CI/CD Testing

In your CI pipeline, add a smoke test after protection.

GitHub Actions

YAML
- 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

Fastlane

Ruby
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)
end

Next 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

Previous
Polymorphic Builds