base on A toolkit to make debugging iOS applications easier šŸš€ # DebugSwift <p align="center"> <img src="https://img.shields.io/badge/Platforms-iOS%2014.0+-blue.svg"/> <img src="https://img.shields.io/github/v/release/DebugSwift/DebugSwift?style=flat&label=Swift%20Package%20Index&color=red"/> <img src="https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2FDebugSwift%2FDebugSwift%2Fbadge%3Ftype%3Dswift-versions"/> <img src="https://img.shields.io/github/license/DebugSwift/DebugSwift?style=flat"/> </p> | <img width="300" src="https://github.com/DebugSwift/DebugSwift/assets/31082311/3d219290-ba08-441a-a4c7-060f946683c2"> | <div align="left" >DebugSwift is a comprehensive toolkit designed to streamline and elevate the debugging experience for Swift-based applications. Whether you are troubleshooting issues or optimizing performance, DebugSwift offers a powerful set of features to make your debugging process more efficient and effective. | |---|---| <img width="1970" alt="Image" src="https://github.com/user-attachments/assets/a569b038-9058-4260-ae7c-47f3376cf629" /> <img width="1970" alt="Image" src="https://github.com/user-attachments/assets/334ccefa-5951-494f-8faa-5f016d39f946" /> <img width="1970" alt="Image" src="https://github.com/user-attachments/assets/246cde3c-7a14-45de-ae01-e810c42d8e65" /> <img width="1970" alt="Image" src="https://github.com/user-attachments/assets/fadde188-dcba-46d8-9460-762f9be98bd6" /> <img width="1970" height="1184" alt="Image" src="https://github.com/user-attachments/assets/8085e55c-a7e6-4e3b-8ceb-8fc7034480fe" /> <img width="1970" alt="Image" src="https://github.com/user-attachments/assets/a435a660-a4b2-4a3f-852e-a7bf0709e75e" /> <img width="1970" alt="Image" src="https://github.com/user-attachments/assets/15f34de1-214f-4bc3-95bc-b25efc2d383e" /> ## šŸ“‹ Table of Contents - [šŸš€ Features](#features) - [šŸ›  Installation & Setup](#installation--setup) - [šŸ”§ Troubleshooting](#troubleshooting) - [šŸ“ Examples](#examples) - [šŸ”§ Configuration](#configuration) ## Requirements - **iOS 14.0+** - **Swift 6.0+** - **Xcode 16.0+** ## Features ### 🌐 Network Inspector - **HTTP Monitoring:** Capture all requests/responses with detailed logs and filtering - **WebSocket Inspector:** Zero-config automatic monitoring of WebSocket connections and frames - **Request Limiting:** Set thresholds to monitor and control API usage - **Smart Content:** Automatic JSON formatting with syntax highlighting - **Encryption Support:** Automatic decryption of encrypted API responses with AES-256/128 and custom decryptors ### ⚔ Performance - **Real-time Metrics:** Monitor CPU, memory, and FPS in real-time - **Memory Leak Detection:** Automatic detection of leaked ViewControllers and Views - **Thread Checker:** Detect main thread violations with detailed stack traces - **Performance Widget:** Overlay displaying live performance stats ### šŸ“± App Tools - **Crash Reports:** Detailed crash analysis with screenshots and stack traces - **Console Logs:** Real-time console output monitoring and filtering - **Device Info:** App version, build, device details, and more - **APNS Tokens:** Easy access and copying of push notification tokens - **Custom Actions:** Add your own debugging actions and info ### šŸŽØ Interface Tools - **Grid Overlay:** Visual alignment grid with customizable colors and opacity - **View Hierarchy:** 3D interactive view hierarchy inspector - **Touch Indicators:** Visual feedback for touch interactions - **Animation Control:** Slow down animations for easier debugging - **View Borders:** Highlight view boundaries with colorization - **SwiftUI Render Tracking (Beta):** Automatically detect and visualize SwiftUI view re-renders with dedicated settings screen ### šŸ“ Resources - **File Browser:** Navigate app sandbox and shared app group containers - **UserDefaults:** View and modify app preferences at runtime - **Keychain:** Inspect keychain entries - **Database Browser:** SQLite and Realm database inspection - **Push Notifications:** Simulate push notifications with templates and test scenarios ## Installation & Setup ### šŸƒ Swift Package Manager (Recommended) Add to your `Package.swift`: ```swift dependencies: [ .package(url: "https://github.com/DebugSwift/DebugSwift.git", from: "2.0.0") ] ``` Or add through Xcode: `File` > `Add Package Dependencies` > Enter URL: ``` https://github.com/DebugSwift/DebugSwift ``` ### šŸŽÆ CocoaPods #### Option 1: Source Distribution (Standard) Add to your `Podfile`: ```ruby pod 'DebugSwift' ``` #### Option 2: XCFramework Distribution (Faster Builds) ⚔ Add to your `Podfile`: ```ruby pod 'DebugSwift', :http => 'https://github.com/DebugSwift/DebugSwift/releases/latest/download/DebugSwift.xcframework.zip' ``` ### šŸŽ Apple Silicon Support DebugSwift **fully supports Apple Silicon Macs** with native arm64 simulator builds! No more architecture exclusions or compatibility issues. **Supported Architectures:** - šŸ“± **iOS Device**: arm64 - šŸ–„ļø **iOS Simulator**: arm64 (Apple Silicon) + x86_64 (Intel) **Migration Note:** If you were using architecture exclusions like `'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'arm64'`, you can now **remove them** as they are no longer needed. ### Basic Setup ```swift import DebugSwift @main class AppDelegate: UIResponder, UIApplicationDelegate { private let debugSwift = DebugSwift() func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { #if DEBUG debugSwift.setup() // debugSwift.setup(disable: [.leaksDetector]) debugSwift.show() #endif return true } } ``` ### Shake to Toggle (Optional) ```swift extension UIWindow { open override func motionEnded(_ motion: UIEvent.EventSubtype, with event: UIEvent?) { super.motionEnded(motion, with: event) #if DEBUG if motion == .motionShake { if let appDelegate = UIApplication.shared.delegate as? AppDelegate { appDelegate.debugSwift.toggle() } } #endif } } ``` ## šŸ”§ Troubleshooting ### Apple Silicon Build Issues If you encounter build errors like `error unsupported Swift architecture` or `DebugSwift.framework only contains x86_64 slice for simulator` on Apple Silicon Macs: #### Solution 1: Update to Latest Version Ensure you're using the latest version of DebugSwift which includes full Apple Silicon support: ```ruby # CocoaPods pod 'DebugSwift', '~> 1.8.1' # Swift Package Manager - update to latest ``` #### Solution 2: Use XCFramework Distribution (Recommended) For faster builds and guaranteed architecture compatibility: ```ruby pod 'DebugSwift', :http => 'https://github.com/DebugSwift/DebugSwift/releases/latest/download/DebugSwift.xcframework.zip' ``` #### Solution 3: Remove Architecture Exclusions If you have custom architecture exclusions in your project, remove them: ```ruby # Remove this from your Podfile or target configuration: # config.build_settings['EXCLUDED_ARCHS[sdk=iphonesimulator*]'] = 'arm64' ``` #### Solution 4: Clean Build Clean your build folder and derived data: ```bash # Xcode Product → Clean Build Folder (āŒ˜ā‡§K) # Command line rm -rf ~/Library/Developer/Xcode/DerivedData ``` ### Build Performance - **XCFramework Distribution**: Up to 50% faster build times - **Source Distribution**: Full source access and debugging capabilities Choose XCFramework for production builds, source for active development. ## Examples ### Enhanced Hierarchy Tree for Deeper Application Insights (Beta) Harness the Power of Visual Information within the iOS Hierarchy Tree to Uncover Intricate Layouts and Element Relationships in Your Application. #### How to Use Simply press and hold the circle button to reveal the Snapshot and Hierarchy for a comprehensive overview. #### Results: ![image8](https://github.com/DebugSwift/DebugSwift/assets/31082311/fdc117a2-e9f9-4246-9e9e-fcae818b7ea1) #### Explore Additional Details Enhance your understanding by pressing and holding on a specific view to reveal information such as: - Class - Subviews - Background Color - Specific attributes based on the type (e.g., UILabel: Text, Font, and TextColor). #### Results: ![image10](https://github.com/DebugSwift/DebugSwift/assets/31082311/7e9c3a8b-3d26-4b7c-b671-1894cb32e562) ### App Custom ViewControllers in Tab Bar ```swift DebugSwift.App.shared.customControllers = { let controller1 = UITableViewController() controller1.title = "Custom TableVC 1" let controller2 = UITableViewController() controller2.title = "Custom TableVC 2" return [controller1, controller2] } ``` ### Custom Debug Actions ```swift // Add custom debugging actions DebugSwift.App.shared.customAction = { [ .init(title: "Development Tools", actions: [ .init(title: "Clear User Data") { UserDefaults.standard.removeObject(forKey: "userData") }, .init(title: "Reset App State") { // Your reset logic here } ]) ] } ``` #### Results: ![image6](https://github.com/DebugSwift/DebugSwift/assets/31082311/f9c23835-e17e-49a8-b971-4b9880403b15) ### App Custom Data ```swift DebugSwift.App.shared.customInfo = { [ .init( title: "Info 1", infos: [ .init(title: "title 1", subtitle: "title 2") ] ) ] } ``` #### Results: ![image5](https://github.com/DebugSwift/DebugSwift/assets/31082311/2a38e758-1418-4f14-805f-432d124ad071) ### APNS Token Integration ```swift // In your AppDelegate func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) { DebugSwift.APNSToken.didRegister(deviceToken: deviceToken) // Your existing token handling code } func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) { DebugSwift.APNSToken.didFailToRegister(error: error) // Your existing error handling code } ``` ## Configuration ### Network Filtering ```swift // Ignore specific URLs DebugSwift.Network.shared.ignoredURLs = ["https://analytics.com"] // Monitor only specific URLs DebugSwift.Network.shared.onlyURLs = ["https://api.myapp.com"] ``` ### Network History Management ```swift // Clear HTTP/HTTPS request history (useful when switching environments) DebugSwift.Network.shared.clearNetworkHistory() // Clear WebSocket connection history await DebugSwift.Network.shared.clearWebSocketHistory() // Clear all network data (HTTP + WebSocket) await DebugSwift.Network.shared.clearAllNetworkData() // Example: Clear network data when switching environments DebugSwift.App.shared.customAction = { [ .init(title: "Environment", actions: [ .init(title: "Switch to Production") { // Your environment switch logic DebugSwift.Network.shared.clearNetworkHistory() }, .init(title: "Switch to Development") { // Your environment switch logic DebugSwift.Network.shared.clearNetworkHistory() } ]) ] } ``` ### Manual URLSessionConfiguration Injection If you create `URLSessionConfiguration` instances **before** calling `DebugSwift.setup()`, you can manually inject the network monitoring protocol: ```swift // Option 1: Inject into existing configuration let config = URLSessionConfiguration.default DebugSwift.Network.shared.injectIntoConfiguration(config) let session = URLSession(configuration: config) // Option 2: Get pre-configured default configuration let config = DebugSwift.Network.shared.defaultConfiguration() let session = URLSession(configuration: config) // Option 3: Get pre-configured ephemeral configuration let config = DebugSwift.Network.shared.ephemeralConfiguration() let session = URLSession(configuration: config) // Option 4: Direct protocol class injection (advanced) var config = URLSessionConfiguration.default var protocolClasses = config.protocolClasses ?? [] protocolClasses.insert(CustomHTTPProtocol.self, at: 0) config.protocolClasses = protocolClasses ``` **Note:** This is particularly useful when migrating from other network debugging tools like Netfox or when working with pre-existing URLSession configurations. ### Network Encryption/Decryption DebugSwift supports automatic decryption of encrypted API responses, making it easier to debug apps with end-to-end encryption. ```swift // Enable decryption feature DebugSwift.Network.shared.setDecryptionEnabled(true) // Register decryption key for specific API endpoints if let key = "your-32-byte-aes-key-here-123456".data(using: .utf8) { DebugSwift.Network.shared.registerDecryptionKey(for: "api.example.com", key: key) } // Register custom decryptor for complex encryption schemes DebugSwift.Network.shared.registerCustomDecryptor(for: "api.myapp.com") { encryptedData in // Your custom decryption logic here return customDecrypt(encryptedData) } ``` ### Selective Features ```swift debugSwift.setup( hideFeatures: [.performance, .interface], // Hide specific tabs disable: [.leaksDetector, .console] // Disable specific monitoring ) ``` ### Beta Features ```swift // Enable beta features (disabled by default) debugSwift.setup( enableBetaFeatures: [.swiftUIRenderTracking] // Enable experimental SwiftUI render tracking ) ``` ### App Group Configuration ```swift // Configure app groups for file browser access DebugSwift.Resources.shared.configureAppGroups([ "group.com.yourcompany.yourapp" ]) ``` ### Performance Monitoring ```swift // Configure memory leak detection DebugSwift.Performance.shared.onLeakDetected { leakData in print("šŸ”“ Memory leak detected: \(leakData.message)") } ``` ### Push Notification Simulation ```swift // Enable push notification simulation DebugSwift.PushNotification.enableSimulation() // Simulate a notification DebugSwift.PushNotification.simulate( title: "Test Notification", body: "This is a test notification" ) ``` ### SwiftUI Render Tracking (Beta) āš ļø **Beta Feature**: SwiftUI render tracking is experimental and must be enabled explicitly. ```swift // First enable the beta feature in setup debugSwift.setup(enableBetaFeatures: [.swiftUIRenderTracking]) // Then enable SwiftUI render tracking DebugSwift.SwiftUIRender.shared.isEnabled = true // Configure persistent overlays (stay visible until manually cleared) DebugSwift.SwiftUIRender.shared.persistentOverlays = true // Set overlay style (border, borderWithCount, none) DebugSwift.SwiftUIRender.shared.overlayStyle = .borderWithCount // Configure overlay duration DebugSwift.SwiftUIRender.shared.overlayDuration = 1.0 // Enable console logging DebugSwift.SwiftUIRender.shared.loggingEnabled = true // Clear render statistics DebugSwift.SwiftUIRender.shared.clearStats() // Clear persistent overlays DebugSwift.SwiftUIRender.shared.clearPersistentOverlays() ``` --- ## ⭐ Support the Project If you find DebugSwift helpful, please consider giving us a star on GitHub! Your support helps us continue improving and adding new features. [![GitHub stars](https://img.shields.io/github/stars/DebugSwift/DebugSwift.svg?style=social&label=Star)](https://github.com/DebugSwift/DebugSwift) ## Contributors Our contributors have made this project possible. Thank you! <a href="https://github.com/DebugSwift/DebugSwift/graphs/contributors"> <img src="https://contrib.rocks/image?repo=DebugSwift/DebugSwift" /> </a> ## Contributing Contributions are welcome! If you have suggestions, improvements, or bug fixes, please submit a pull request. Let's make DebugSwift even more powerful together! ## Repo Activity ![Alt](https://repobeats.axiom.co/api/embed/53a4d8a27ad851f52451b14b9a1671e7124f88e8.svg "Repobeats analytics image") ## Star History [![Star History Chart](https://api.star-history.com/svg?repos=DebugSwift/DebugSwift&type=Date)](https://star-history.com/#DebugSwift/DebugSwift&Date) ## License DebugSwift is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. ## References - [InAppViewDebugger](https://github.com/indragiek/InAppViewDebugger) - [CocoaDebug](https://github.com/CocoaDebug/CocoaDebug) - [DBDebugToolkit](https://github.com/dbukowski/DBDebugToolkit) - [LeakedViewControllerDetector](https://github.com/Janneman84/LeakedViewControllerDetector)", Assign "at most 3 tags" to the expected json: {"id":"12656","tags":[]} "only from the tags list I provide: [{"id":77,"name":"3d"},{"id":89,"name":"agent"},{"id":17,"name":"ai"},{"id":54,"name":"algorithm"},{"id":24,"name":"api"},{"id":44,"name":"authentication"},{"id":3,"name":"aws"},{"id":27,"name":"backend"},{"id":60,"name":"benchmark"},{"id":72,"name":"best-practices"},{"id":39,"name":"bitcoin"},{"id":37,"name":"blockchain"},{"id":1,"name":"blog"},{"id":45,"name":"bundler"},{"id":58,"name":"cache"},{"id":21,"name":"chat"},{"id":49,"name":"cicd"},{"id":4,"name":"cli"},{"id":64,"name":"cloud-native"},{"id":48,"name":"cms"},{"id":61,"name":"compiler"},{"id":68,"name":"containerization"},{"id":92,"name":"crm"},{"id":34,"name":"data"},{"id":47,"name":"database"},{"id":8,"name":"declarative-gui "},{"id":9,"name":"deploy-tool"},{"id":53,"name":"desktop-app"},{"id":6,"name":"dev-exp-lib"},{"id":59,"name":"dev-tool"},{"id":13,"name":"ecommerce"},{"id":26,"name":"editor"},{"id":66,"name":"emulator"},{"id":62,"name":"filesystem"},{"id":80,"name":"finance"},{"id":15,"name":"firmware"},{"id":73,"name":"for-fun"},{"id":2,"name":"framework"},{"id":11,"name":"frontend"},{"id":22,"name":"game"},{"id":81,"name":"game-engine "},{"id":23,"name":"graphql"},{"id":84,"name":"gui"},{"id":91,"name":"http"},{"id":5,"name":"http-client"},{"id":51,"name":"iac"},{"id":30,"name":"ide"},{"id":78,"name":"iot"},{"id":40,"name":"json"},{"id":83,"name":"julian"},{"id":38,"name":"k8s"},{"id":31,"name":"language"},{"id":10,"name":"learning-resource"},{"id":33,"name":"lib"},{"id":41,"name":"linter"},{"id":28,"name":"lms"},{"id":16,"name":"logging"},{"id":76,"name":"low-code"},{"id":90,"name":"message-queue"},{"id":42,"name":"mobile-app"},{"id":18,"name":"monitoring"},{"id":36,"name":"networking"},{"id":7,"name":"node-version"},{"id":55,"name":"nosql"},{"id":57,"name":"observability"},{"id":46,"name":"orm"},{"id":52,"name":"os"},{"id":14,"name":"parser"},{"id":74,"name":"react"},{"id":82,"name":"real-time"},{"id":56,"name":"robot"},{"id":65,"name":"runtime"},{"id":32,"name":"sdk"},{"id":71,"name":"search"},{"id":63,"name":"secrets"},{"id":25,"name":"security"},{"id":85,"name":"server"},{"id":86,"name":"serverless"},{"id":70,"name":"storage"},{"id":75,"name":"system-design"},{"id":79,"name":"terminal"},{"id":29,"name":"testing"},{"id":12,"name":"ui"},{"id":50,"name":"ux"},{"id":88,"name":"video"},{"id":20,"name":"web-app"},{"id":35,"name":"web-server"},{"id":43,"name":"webassembly"},{"id":69,"name":"workflow"},{"id":87,"name":"yaml"}]" returns me the "expected json"