{"id":47751367,"url":"https://github.com/kibotu/caliper","last_synced_at":"2026-04-03T03:12:10.870Z","repository":{"id":323666809,"uuid":"1091763854","full_name":"kibotu/caliper","owner":"kibotu","description":"iOS app size analyzer with LinkMap parsing, asset tracking, and module ownership. Generate interactive reports for App Store optimization and CI/CD integration.","archived":false,"fork":false,"pushed_at":"2025-11-20T16:34:21.000Z","size":1445,"stargazers_count":5,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-11-20T18:20:42.305Z","etag":null,"topics":["analyzer","app-size","asset-analysis","ci-cd","command-line-tool","developer-tools","html-reports","ios","module-ownership","monitoring","performance","ruler","swift","swift-package-manager","xcode"],"latest_commit_sha":null,"homepage":"https://medium.com/@kibotu/where-do-all-the-bytes-in-an-ios-app-actually-go-42e020cdcde9","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kibotu.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"custom":"https://paypal.me/janrabe/5"}},"created_at":"2025-11-07T13:38:15.000Z","updated_at":"2025-11-20T16:32:20.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/kibotu/caliper","commit_stats":null,"previous_names":["kibotu/caliper"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/kibotu/caliper","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kibotu%2Fcaliper","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kibotu%2Fcaliper/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kibotu%2Fcaliper/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kibotu%2Fcaliper/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kibotu","download_url":"https://codeload.github.com/kibotu/caliper/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kibotu%2Fcaliper/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31330673,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-03T02:17:30.558Z","status":"ssl_error","status_checked_at":"2026-04-03T02:17:30.071Z","response_time":107,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["analyzer","app-size","asset-analysis","ci-cd","command-line-tool","developer-tools","html-reports","ios","module-ownership","monitoring","performance","ruler","swift","swift-package-manager","xcode"],"created_at":"2026-04-03T03:12:10.100Z","updated_at":"2026-04-03T03:12:10.862Z","avatar_url":"https://github.com/kibotu.png","language":"Swift","funding_links":["https://paypal.me/janrabe/5"],"categories":[],"sub_categories":[],"readme":"# Caliper \n\n[![Build](https://github.com/kibotu/caliper/actions/workflows/build.yml/badge.svg)](https://github.com/kibotu/caliper/actions/workflows/build.yml) [![GitHub Release](https://img.shields.io/github/v/release/kibotu/caliper)](https://github.com/kibotu/caliper/releases)\n[![Static Badge](https://img.shields.io/badge/iOS-26-blue)](https://developer.apple.com/documentation/ios-ipados-release-notes/ios-ipados-26-release-notes)\n[![Static Badge](https://img.shields.io/badge/Swift%206.0%20-%20orange)](https://www.swift.org/blog/announcing-swift-6/)\n\n**Your iOS app's size under control.** Caliper analyzes bundle sizes down to the module level, tracks team ownership, and generates beautiful interactive reports. Know exactly what's taking up space, who owns it, and where to optimize—all from a single command.\n\n## [Demo HTML report](https://kibotu.github.io/caliper/)\n\n\u003ctable\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"33%\"\u003e\n      \u003ca href=\"docs/breakdown.png\"\u003e\n        \u003cimg src=\"docs/breakdown.png\" alt=\"Module Size Breakdown\" width=\"100%\"\u003e\n      \u003c/a\u003e\n      \u003cp align=\"center\"\u003e\u003cem\u003eModule Size Breakdown\u003c/em\u003e\u003c/p\u003e\n    \u003c/td\u003e\n    \u003ctd width=\"33%\"\u003e\n      \u003ca href=\"docs/insights.png\"\u003e\n        \u003cimg src=\"docs/insights.png\" alt=\"Size Insights\" width=\"100%\"\u003e\n      \u003c/a\u003e\n      \u003cp align=\"center\"\u003e\u003cem\u003eSize Insights\u003c/em\u003e\u003c/p\u003e\n    \u003c/td\u003e\n    \u003ctd width=\"33%\"\u003e\n      \u003ca href=\"docs/ownership.png\"\u003e\n        \u003cimg src=\"docs/ownership.png\" alt=\"Module Ownership\" width=\"100%\"\u003e\n      \u003c/a\u003e\n      \u003cp align=\"center\"\u003e\u003cem\u003eModule Ownership\u003c/em\u003e\u003c/p\u003e\n    \u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\n## Quick Start\n\n```bash\n# Build\nswift build -c release\n\n# Analyze IPA with all features\n.build/release/caliper \\\n  --ipa-path MyApp.ipa \\\n  --link-map-path MyApp-LinkMap.txt \\\n  --ownership-file module-ownership.yml \\\n  --package-resolved-path Package.resolved\n```\n\nGenerates `report.json` and `report.html` in the current directory.\n\n## Features\n\n- **Binary Size Analysis** - Accurate per-module binary sizes from LinkMap files\n- **Asset Tracking** - Detailed breakdown of images, storyboards, and resources\n- **Module Ownership** - Track which team owns which modules\n- **Version Tracking** - Swift package version information from Package.resolved\n- **Interactive Reports** - Searchable HTML reports with filtering and sorting\n- **Size Metrics** - Both compressed (IPA) and uncompressed (installed) sizes\n- **Automatic App Detection** - Identifies and tags main app module automatically\n\n## Installation\n\n### Build from Source\n\n```bash\ngit clone https://github.com/kibotu/caliper.git\ncd caliper\nswift build -c release\n\n# Binary will be at: .build/release/caliper\n```\n\n### System-wide Install\n\n```bash\nmake install\n# Installs to /usr/local/bin/caliper\n```\n\n### Swift Mint\n\n```bash\n# Install\nmint install kibotu/caliper\n\n# Run\nmint run kibotu/caliper --ipa-path MyApp.ipa\n\n# Or install globally\nmint install kibotu/caliper@main\ncaliper --ipa-path MyApp.ipa\n```\n\n## Usage\n\n### Basic IPA Analysis\n\nMinimum required input - analyzes bundle structure and resources:\n\n```bash\n.build/release/caliper --ipa-path MyApp.ipa\n```\n\n### With Binary Size Data\n\nAdd LinkMap for accurate per-module binary sizes:\n\n```bash\n.build/release/caliper \\\n  --ipa-path MyApp.ipa \\\n  --link-map-path MyApp-LinkMap.txt\n```\n\n**How to generate LinkMap:**\n1. Xcode → Build Settings\n2. Search for \"Write Link Map File\"\n3. Set to `YES`\n4. Build your app\n5. Find LinkMap at: `~/Library/Developer/Xcode/DerivedData/YourApp-xxx/Build/Intermediates.noindex/YourApp.build/Release-iphoneos/YourApp.build/YourApp-LinkMap-normal-arm64.txt`\n\n[![Screenshot](docs/xcode-link-map.png)](docs/xcode-link-map.png)\n\n### With Module Ownership\n\nTrack which team owns which modules:\n\n```bash\n.build/release/caliper \\\n  --ipa-path MyApp.ipa \\\n  --link-map-path MyApp-LinkMap.txt \\\n  --ownership-file module-ownership.yml\n```\n\n**module-ownership.yml example:**\n\n```yaml\n# Pattern matching with wildcards\n- identifier: \"*CoreFeature*\"\n  owner: Core Team\n  internal: true\n\n- identifier: \"MyApp\"\n  owner: App Team\n  internal: true\n\n- identifier: \"ThirdParty*\"\n  owner: External\n```\n\n**Pattern syntax:**\n- `*` = any characters\n- `?` = single character\n- `internal: true` = marks as first-party code\n- `owner` = team/group name for reporting\n\n**Note:** The main app module is automatically tagged with `owner: \"App\"` and `internal: true` even without an ownership file.\n\n### With Package Versions\n\nInclude Swift package version information:\n\n```bash\n.build/release/caliper \\\n  --ipa-path MyApp.ipa \\\n  --link-map-path MyApp-LinkMap.txt \\\n  --package-resolved-path Package.resolved\n```\n\n**Where to find Package.resolved:**\n- Xcode projects: `YourProject.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved`\n- SPM projects: `Package.resolved` in project root\n\n### With Package Name Mapping\n\nFor namespaced packages (e.g., internal packages):\n\n```bash\n.build/release/caliper \\\n  --ipa-path MyApp.ipa \\\n  --link-map-path MyApp-LinkMap.txt \\\n  --package-resolved-path Package.resolved \\\n  --package-mapping-file package-name-mapping.yml\n```\n\n**package-name-mapping.yml example:**\n\n```yaml\n- moduleName: AdjustSDK\n  packageIdentity: com.company.adjust-sdk\n\n- moduleName: InternalCore\n  packageIdentity: internal.core-framework\n```\n\n## Parameters\n\n| Parameter | Required | Description |\n|-----------|----------|-------------|\n| `--ipa-path` | ✅ Yes | Path to the IPA file to analyze |\n| `--link-map-path` | ⬜ No | Path to LinkMap file for accurate binary sizes |\n| `--ownership-file` | ⬜ No | YAML file with module ownership patterns |\n| `--package-resolved-path` | ⬜ No | Path to Package.resolved for version tracking |\n| `--package-mapping-file` | ⬜ No | YAML file for namespaced package mappings |\n\n## Data Sources\n\n| Data Type | Source | Compression | Notes |\n|-----------|--------|-------------|-------|\n| **Module Names** | IPA structure (.framework, .bundle) | - | Extracted from bundle hierarchy |\n| **Binary Sizes** | LinkMap file | Uncompressed | Compiled code size per module |\n| **Asset Sizes** | IPA + .car files | Both | Images: compressed (IPA) + uncompressed (installed) |\n| **Resource Files** | IPA archive | Compressed | .plist, .strings, .nib, .storyboardc, etc. |\n| **Package Versions** | Package.resolved | - | Swift package dependency versions |\n| **Total IPA Size** | IPA file | Compressed | Download/App Store size |\n| **Total Install Size** | Unzipped IPA | Uncompressed | Actual installed app size |\n| **Asset Catalog Details** | .car files via assetutil | Uncompressed | Parsed with xcrun assetutil |\n\n### Compressed vs Uncompressed\n\n- **Compressed** (in IPA): What users download from App Store\n- **Uncompressed**: Actual size on device after installation\n- **Binary sizes** (from LinkMap): Always uncompressed executable code\n- **Asset compression**: Varies by file type (PNG, JPEG, etc.)\n\n## Output\n\n### JSON Report (`report.json`)\n\n```json\n{\n  \"app\": {\n    \"name\": \"MyApp\",\n    \"version\": \"1.2.3\",\n    \"bundleId\": \"com.company.myapp\"\n  },\n  \"modules\": {\n    \"CoreModule\": {\n      \"name\": \"CoreModule\",\n      \"owner\": \"Core Team\",\n      \"internal\": true,\n      \"version\": \"2.1.0\",\n      \"binarySize\": 1234567,\n      \"imageSize\": 234567,\n      \"imageFileSize\": 345678,\n      \"proguard\": 2345678,\n      \"resources\": {\n        \"png\": { \"size\": 123456, \"count\": 42 },\n        \"storyboardc\": { \"size\": 45678, \"count\": 3 }\n      },\n      \"top\": {\n        \"Assets.car\": 98765,\n        \"Background.png\": 12345\n      }\n    }\n  },\n  \"totalPackageSize\": 12345678,\n  \"totalInstallSize\": 23456789\n}\n```\n\n**Field descriptions:**\n\n| Field | Unit | Description |\n|-------|------|-------------|\n| `binarySize` | bytes | Compiled code size (from LinkMap) |\n| `imageSize` | bytes | Compressed image assets in IPA |\n| `imageFileSize` | bytes | Uncompressed image assets |\n| `proguard` | bytes | Total uncompressed module size |\n| `resources` | object | File types with size and count |\n| `top` | object | Top 30 largest files in module |\n| `totalPackageSize` | bytes | IPA file size (compressed) |\n| `totalInstallSize` | bytes | Installed app size (uncompressed) |\n\n### HTML Report (`report.html`)\n\nInteractive web interface with:\n- 🔍 Search and filter modules\n- 📊 Sort by size, binary size, or name\n- 📂 Expandable module details\n- 🎨 Resource breakdowns by file type\n- 📈 Top 10 largest files per module\n- 👥 Filter by owner/team\n- 🏷️ Internal vs external module filtering\n\n## CI/CD Integration\n\n### Jenkins Pipeline\n\n```groovy\npipeline {\n    agent any\n    \n    stages {\n        stage('Build App') {\n            steps {\n                // Your app build steps here\n                sh 'xcodebuild -configuration Release ...'\n            }\n        }\n        \n        stage('Analyze App Size') {\n            steps {\n                // Clone and build Caliper\n                dir('caliper') {\n                    git url: 'https://github.com/kibotu/caliper.git'\n                    sh 'swift build -c release'\n                }\n                \n                // Run analysis\n                sh '''\n                    caliper/.build/release/caliper \\\n                        --ipa-path build/MyApp.ipa \\\n                        --link-map-path build/LinkMap.txt \\\n                        --ownership-file config/module-ownership.yml \\\n                        --package-resolved-path Package.resolved\n                '''\n                \n                // Archive reports\n                archiveArtifacts artifacts: 'report.json,report.html', allowEmptyArchive: false\n                \n                // Publish HTML report\n                publishHTML([\n                    reportDir: '.',\n                    reportFiles: 'report.html',\n                    reportName: 'App Size Report',\n                    keepAll: true,\n                    alwaysLinkToLastBuild: true\n                ])\n            }\n        }\n        \n        stage('Check Size Thresholds') {\n            steps {\n                script {\n                    // Parse JSON and check thresholds\n                    def report = readJSON file: 'report.json'\n                    def maxSize = 100 * 1024 * 1024 // 100 MB\n                    \n                    if (report.totalPackageSize \u003e maxSize) {\n                        error \"App size ${report.totalPackageSize} exceeds threshold ${maxSize}\"\n                    }\n                }\n            }\n        }\n    }\n}\n```\n\n### GitHub Actions\n\n```yaml\nname: App Size Analysis\n\non:\n  pull_request:\n    branches: [main]\n  push:\n    branches: [main]\n\njobs:\n  analyze:\n    runs-on: macos-13\n    \n    steps:\n      - name: Checkout Code\n        uses: actions/checkout@v4\n      \n      - name: Setup Xcode\n        uses: maxim-lobanov/setup-xcode@v1\n        with:\n          xcode-version: '15.0'\n      \n      - name: Build App\n        run: |\n          xcodebuild -workspace MyApp.xcworkspace \\\n            -scheme MyApp \\\n            -configuration Release \\\n            -archivePath build/MyApp.xcarchive \\\n            archive\n          \n          xcodebuild -exportArchive \\\n            -archivePath build/MyApp.xcarchive \\\n            -exportPath build \\\n            -exportOptionsPlist ExportOptions.plist\n      \n      - name: Checkout Caliper\n        uses: actions/checkout@v4\n        with:\n          repository: kibotu/caliper\n          path: caliper\n      \n      - name: Build Caliper\n        run: |\n          cd caliper\n          swift build -c release\n      \n      - name: Analyze App Size\n        run: |\n          caliper/.build/release/caliper \\\n            --ipa-path build/MyApp.ipa \\\n            --link-map-path build/LinkMap.txt \\\n            --ownership-file config/module-ownership.yml \\\n            --package-resolved-path MyApp.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved\n      \n      - name: Upload Reports\n        uses: actions/upload-artifact@v4\n        with:\n          name: size-reports\n          path: |\n            report.json\n            report.html\n          retention-days: 90\n      \n      - name: Comment PR with Size\n        if: github.event_name == 'pull_request'\n        uses: actions/github-script@v7\n        with:\n          script: |\n            const fs = require('fs');\n            const report = JSON.parse(fs.readFileSync('report.json', 'utf8'));\n            const sizeMB = (report.totalPackageSize / 1024 / 1024).toFixed(2);\n            const installMB = (report.totalInstallSize / 1024 / 1024).toFixed(2);\n            \n            const body = `## 📊 App Size Report\n            \n            - **IPA Size:** ${sizeMB} MB\n            - **Install Size:** ${installMB} MB\n            - **Modules:** ${Object.keys(report.modules).length}\n            \n            [View detailed report](../actions/runs/${context.runId})`;\n            \n            github.rest.issues.createComment({\n              issue_number: context.issue.number,\n              owner: context.repo.owner,\n              repo: context.repo.repo,\n              body: body\n            });\n```\n\n## Required Tools\n\nCaliper requires the following command-line tools to be installed:\n\n| Tool | Usage | Installation | Version Check |\n|------|-------|--------------|---------------|\n| **Swift** | Build Caliper | Xcode Command Line Tools | `swift --version` |\n| **unzip** | Extract IPA files | Pre-installed on macOS | `unzip -v` |\n| **xcrun** | Run Xcode tools | Xcode Command Line Tools | `xcrun --version` |\n| **assetutil** | Parse .car asset catalogs | Part of iOS SDK | `xcrun --sdk iphoneos assetutil --version` |\n\n### Install Xcode Command Line Tools\n\n```bash\nxcode-select --install\n```\n\n### Verify Installation\n\n```bash\n# Check Swift\nswift --version\n# Should show: Swift version 6.0 or later\n\n# Check unzip\nwhich unzip\n# Should show: /usr/bin/unzip\n\n# Check xcrun\nxcrun --version\n# Should show: xcrun version X.X\n\n# Check assetutil availability\nxcrun --sdk iphoneos assetutil --version 2\u003e/dev/null \u0026\u0026 echo \"✅ assetutil available\" || echo \"❌ assetutil not found\"\n```\n\n## Requirements\n\n- **macOS** 14.0 or later\n- **Xcode** 16.0 or later\n- **Swift** 6.0 or later\n- **Xcode Command Line Tools** (includes unzip, xcrun, assetutil)\n\n\n### Pre-Flight Checklist\n\nBefore diving into analysis, make sure you have the right build configuration. Here's a quick checklist to maximize the value you'll get from Caliper:\n\n**Build Settings (for Release configuration):**\n- [ ] `LD_GENERATE_MAP_FILE` = `YES` (enables LinkMap)\n- [ ] `DEAD_CODE_STRIPPING` = `YES` (removes unused code)\n- [ ] `STRIP_INSTALLED_PRODUCT` = `YES` (strips debug symbols)\n- [ ] `STRIP_SWIFT_SYMBOLS` = `YES` (removes reflection metadata)\n- [ ] `SWIFT_OPTIMIZATION_LEVEL` = `-Osize` (if size \u003e speed)\n- [ ] Build configuration = **Release** (Debug builds are much larger!)\n\n**Build Command:**\n- [ ] Using `CODE_SIGNING_REQUIRED=NO` for faster CI builds\n- [ ] Building with `ONLY_ACTIVE_ARCH=NO` to include all architectures\n- [ ] Using `-sdk iphoneos` (not simulator)\n\n**Optional but Valuable:**\n- [ ] Create `module-ownership.yml` to map modules to teams\n- [ ] Create `package-name-mapping.yml` if you use forked dependencies\n- [ ] Save Package.resolved for version tracking\n\n### Common Issues \u0026 Solutions\n\n**\"I can't find the LinkMap file!\"**\n- Make sure you built with **Release** configuration (not Debug)\n- Check that `LD_GENERATE_MAP_FILE` is set to `YES` in Build Settings\n- Clean your build folder and rebuild to ensure it generates fresh\n- Use this command to locate it: `find ~/Library/Developer/Xcode/DerivedData -name \"*LinkMap-normal-arm64.txt\" -type f`\n- The path varies between regular builds and archives—check both locations mentioned earlier\n- Verify you're building for device (`-sdk iphoneos`), not simulator\n\n**\"My build fails with code signing errors\"**\n- If using unsigned builds, check for required entitlements (HealthKit, Apple Pay, iCloud, etc.)\n- These entitlements require proper code signing—you can't skip it\n- Options:\n  1. Create a separate \"size-analysis\" scheme without these entitlements\n  2. Use proper code signing (slower but necessary)\n  3. Temporarily remove the capabilities for analysis builds\n\n**\"My binary size seems wrong or too small\"**\n- LinkMap only shows compiled code, not resources or embedded frameworks\n- Make sure you're analyzing arm64 (device), not x86_64/arm64 (simulator)\n- Debug builds are 2-3x larger than Release—always use Release for analysis\n- If the number seems too small, you might be missing dynamic frameworks\n- Universal builds include multiple architectures—check you're analyzing the right one\n\n**\"Asset sizes don't match what I expect\"**\n- Asset catalog sizes shown by `assetutil` are **uncompressed** (installed size on device)\n- IPA sizes are **compressed** (download size from App Store)\n- Both numbers are correct, they just measure different things\n- App Thinning further reduces what users actually download\n- Example: 50 MB assets → 30 MB in IPA → 20 MB after thinning for specific device\n\n**\"Modules aren't matching teams in the ownership report\"**\n- Check your `module-ownership.yml` patterns—are they specific enough?\n- Module names might not match what you expect—check the report to see actual names first\n- Wildcards are your friend: `*Feature*` is more forgiving than exact matches\n- Order matters: more specific patterns should come before generic ones\n- SPM packages often have different module names than repository names\n\n**\"The HTML report won't open or looks broken\"**\n- Make sure you're opening `report.html` in a modern browser (Chrome, Firefox, Safari)\n- Check that `report.json` exists in the same directory\n- Some browsers block local file access—try hosting it with `python3 -m http.server` and open via localhost\n- If the JSON is very large (\u003e50 MB), it might be slow to load—be patient\n\n**\"Caliper crashes or hangs\"**\n- Very large LinkMap files (\u003e500 MB) can be slow to parse—give it time\n- Make sure you have enough RAM (LinkMap parsing can use 2-3 GB for large apps)\n- Check that your input files aren't corrupted (try opening them manually)\n- If analyzing a massive app (\u003e1 GB), expect analysis to take several minutes\n\n## Troubleshooting\n\n### \"assetutil not found\" or .car parsing fails\n\n**Solution:** Install full Xcode (not just Command Line Tools):\n```bash\n# Install from Mac App Store or:\nxcode-select --install\nsudo xcode-select --switch /Applications/Xcode.app\n```\n\n### LinkMap file not found\n\n**Solution:** Enable LinkMap generation in Xcode:\n1. Project Settings → Build Settings\n2. Search: \"Write Link Map File\"\n3. Set to: `YES`\n4. Clean and rebuild\n\n### Module names don't match Package.resolved\n\n**Solution:** Use `--package-mapping-file` to map module names to package identities.\n\n### Large IPA takes too long\n\n**Solution:** The tool processes files sequentially. Progress is shown in the terminal. For very large IPAs (\u003e500MB), analysis may take 2-5 minutes.\n\n## Inspiration\n\nInspired by [Spotify's Ruler](https://github.com/spotify/ruler) - adapted for iOS with native Swift implementation and iOS-specific features like asset catalog parsing and LinkMap analysis.\n\n## Contributing\n\nContributions welcome! This tool helps iOS teams monitor and optimize app size metrics.\n\n## License\n\n```\nCopyright 2025 Jan Rabe \u0026 CHECK24\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n   http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkibotu%2Fcaliper","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkibotu%2Fcaliper","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkibotu%2Fcaliper/lists"}