@leejungkiin/awkit 1.0.5 → 1.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,9 +4,10 @@ description: >-
4
4
  iOS Reverse Engineering specialist. Reads decrypted IPA output (class-dump headers,
5
5
  Hopper/IDA disassembly, resources, Info.plist) and rebuilds the app from scratch using
6
6
  modern Swift + SwiftUI + Clean Architecture (MVVM).
7
+ UI-First approach: design and approve UI visuals before coding logic.
7
8
  Includes framework detection to reuse existing dependencies.
8
9
  author: Antigravity Team
9
- version: 1.0.0
10
+ version: 2.0.0
10
11
  trigger: conditional
11
12
  activation_keywords:
12
13
  - "/reverse-ios"
@@ -24,10 +25,11 @@ platform: ios
24
25
  sibling_skill: smali-to-kotlin (Android counterpart)
25
26
  ---
26
27
 
27
- # 🍎 Smali-to-Swift Skill
28
+ # 🍎 Smali-to-Swift Skill v2 — UI-First
28
29
 
29
30
  > **Purpose:** Transform decrypted iOS IPA (class-dump headers, disassembly, resources, plist) into a modern Swift app with SwiftUI, Clean Architecture, and MVVM.
30
- > **Philosophy:** "Read ObjC headers to understand WHAT and WHY Write Swift for HOW."
31
+ > **Philosophy:** "Map Blueprint UI FirstLogic Behind"
32
+ > **Key Change (v2):** UI is designed and approved BEFORE coding any business logic.
31
33
 
32
34
  ---
33
35
 
@@ -40,7 +42,7 @@ sibling_skill: smali-to-kotlin (Android counterpart)
40
42
  | Detect & reuse third-party frameworks | Crack/bypass DRM or jailbreak |
41
43
  | Extract only needed resources (on-demand) | Mass-copy assets blindly |
42
44
  | Set up Clean Architecture project structure | Handle Android reverse engineering |
43
- | Scan IPA frameworks for dependency reuse | Submit to App Store |
45
+ | Code UI first, then wire logic behind | Submit to App Store |
44
46
 
45
47
  → For Android reverse engineering → sibling skill: `smali-to-kotlin`
46
48
  → After rebuild complete → use `/test` or `/deploy` workflows
@@ -55,7 +57,7 @@ When this skill is active, the agent becomes:
55
57
  > - Master at reading ObjC/Swift class-dump headers and ARM disassembly
56
58
  > - Fluent in Clean Architecture + MVVM + SwiftUI
57
59
  > - Knows when to reuse vs rewrite third-party frameworks
58
- > - Enforces resource-on-demand principle (zero bloat)
60
+ > - Enforces UI-First and resource-on-demand principles
59
61
 
60
62
  ---
61
63
 
@@ -74,17 +76,12 @@ When this skill is active, the agent becomes:
74
76
  ### What we get from an IPA:
75
77
  ```
76
78
  Payload/App.app/
77
- ├── App # Mach-O binary (encrypted → need decrypt first)
78
- ├── Info.plist # App metadata (bundle ID, permissions, URL schemes)
79
- ├── Frameworks/ # Embedded frameworks (.framework / .dylib)
80
- │ ├── SomeSDK.framework/
81
- │ └── libswiftCore.dylib
79
+ ├── App # Mach-O binary (need decrypt first)
80
+ ├── Info.plist # App metadata
81
+ ├── Frameworks/ # Embedded frameworks
82
82
  ├── Assets.car # Compiled asset catalog
83
83
  ├── Base.lproj/ # Storyboards / XIBs (compiled)
84
- ├── Main.storyboardc/
85
- │ └── LaunchScreen.storyboardc/
86
- ├── *.nib # Compiled XIB files
87
- ├── *.momd # Core Data models (compiled)
84
+ ├── *.nib / *.momd # Compiled UIKit / Core Data
88
85
  ├── embedded.mobileprovision # Provisioning profile
89
86
  ├── _CodeSignature/ # Code signing
90
87
  └── [other resources: json, png, html, js, fonts...]
@@ -106,10 +103,10 @@ Payload/App.app/
106
103
  | Purpose | Technology | Replaces |
107
104
  |---------|-----------|----------|
108
105
  | **Network** | URLSession + async/await | AFNetworking / Alamofire (evaluate) |
109
- | **JSON** | Codable (Swift built-in) | NSJSONSerialization / Mantle / ObjectMapper |
106
+ | **JSON** | Codable (Swift built-in) | NSJSONSerialization / Mantle |
110
107
  | **Local DB** | SwiftData (iOS 17+) or Core Data | Raw SQLite / FMDB / Realm |
111
108
  | **Preferences** | UserDefaults / @AppStorage | NSUserDefaults direct |
112
- | **Keychain** | KeychainAccess (or custom wrapper) | Raw Security.framework |
109
+ | **Keychain** | KeychainAccess (or custom) | Raw Security.framework |
113
110
  | **Image Loading** | AsyncImage / Kingfisher / Nuke | SDWebImage (evaluate) |
114
111
  | **Async** | Swift Concurrency (async/await, actors) | GCD / NSOperation / PromiseKit |
115
112
 
@@ -130,33 +127,22 @@ always_replace:
130
127
  Mantle/ObjectMapper: "Codable"
131
128
  GCD_dispatch_async: "Task { } / async-await"
132
129
  NSOperation: "TaskGroup / async let"
133
- NSTimer: "Timer.publish (Combine) or Task.sleep"
134
- UIAlertView: "SwiftUI .alert modifier"
135
- UIActionSheet: "SwiftUI .confirmationDialog"
136
130
  UITableView: "List / LazyVStack"
137
131
  UICollectionView: "LazyVGrid / LazyHGrid"
138
- UIPageViewController: "TabView with .page style"
139
132
  Storyboard_segues: "NavigationStack + NavigationLink"
140
- NSNotificationCenter_addObserver: "NotificationCenter.notifications (AsyncSequence)"
141
133
  KVO: "@Observable macro"
142
134
  Delegate_patterns: "AsyncStream or closures"
143
135
  Target_Action: "SwiftUI action closures"
144
136
 
145
137
  evaluate_before_replacing:
146
- Alamofire: "Keep if deeply used for interceptors/retry, otherwise → URLSession"
147
- SDWebImage: "Replace with AsyncImage + Kingfisher"
148
- Realm: "Migrate to SwiftData (if iOS 17+)"
149
- RxSwift: "Migrate to async/await + AsyncSequence (gradual)"
150
- SnapKit: "Replace with SwiftUI layout"
151
- Masonry: "Replace with SwiftUI layout"
152
- MBProgressHUD: "SwiftUI .overlay + ProgressView"
153
- SVProgressHUD: "SwiftUI .overlay + ProgressView"
154
- IQKeyboardManager: "SwiftUI handles keyboard automatically"
138
+ Alamofire: "Keep if deeply used, else → URLSession"
139
+ SDWebImage: " AsyncImage + Kingfisher"
140
+ Realm: " SwiftData (if iOS 17+)"
141
+ RxSwift: " async/await + AsyncSequence"
142
+ SnapKit: " SwiftUI layout"
155
143
 
156
144
  keep_as_is:
157
145
  - "Firebase SDKs (use latest via SPM)"
158
- - "Google Sign-In"
159
- - "Facebook SDK (latest)"
160
146
  - "Apple frameworks (MapKit, CoreLocation, AVFoundation, etc.)"
161
147
  - "Native C/C++ libraries (.dylib)"
162
148
  - "CryptoKit (Apple native)"
@@ -164,492 +150,50 @@ keep_as_is:
164
150
 
165
151
  ---
166
152
 
167
- ## 📋 EXECUTION PIPELINE (6 Steps)
168
-
169
- > **Rule:** Always complete one step fully before moving to the next.
170
- > **Rule:** After each step, create a checkpoint summary for the user.
171
-
172
- ### Step 0: Framework Scanner (PRE-STEP — Always First) 🔍
173
-
174
- **Purpose:** Scan the IPA structure to identify all third-party frameworks before any coding.
175
-
176
- **Process:**
177
- 1. **Scan `Frameworks/` directory:**
178
- ```
179
- Frameworks/Alamofire.framework → Alamofire (network)
180
- Frameworks/SDWebImage.framework → SDWebImage (image loading)
181
- Frameworks/Realm.framework → Realm (database)
182
- Frameworks/FBSDKCoreKit.framework → Facebook SDK
183
- Frameworks/GoogleSignIn.framework → Google Sign-In
184
- ```
185
-
186
- 2. **Scan class-dump headers for imports:**
187
- ```
188
- #import <AFNetworking/...> → AFNetworking
189
- #import <Masonry/...> → Masonry (auto-layout)
190
- #import <MBProgressHUD/...> → MBProgressHUD
191
- @import Firebase; → Firebase SDK
192
- @import GoogleMobileAds; → AdMob
193
- ```
194
-
195
- 3. **Check Mach-O linked frameworks:**
196
- ```bash
197
- otool -L Payload/App.app/App | grep -v /System | grep -v /usr/lib
198
- ```
199
-
200
- 4. **Check embedded dylibs:**
201
- ```bash
202
- find Payload/App.app -name "*.dylib" -o -name "*.framework" | sort
203
- ```
204
-
205
- 5. **Check for CocoaPods / SPM markers:**
206
- ```
207
- Pods/ directory presence → was using CocoaPods
208
- .package.resolved → was using SPM
209
- ```
210
-
211
- 6. **Output: Framework Detection Report**
212
- ```markdown
213
- ## 📦 Framework Detection Report
214
-
215
- ### ✅ Can Reuse (add to Package.swift / Podfile)
216
- | Framework | Detected | Latest Version | Action |
217
- |-----------|----------|----------------|--------|
218
- | Alamofire | Frameworks/Alamofire.framework | 5.9.0 | Evaluate |
219
- | Kingfisher | (header import) | 7.12.0 | Add via SPM |
220
-
221
- ### 🔄 Must Replace (legacy)
222
- | Old Framework | Detected | Modern Replacement |
223
- |---------------|----------|-------------------|
224
- | AFNetworking | Frameworks/AFNetworking.framework | URLSession async/await |
225
- | Masonry | header imports | SwiftUI layout |
226
-
227
- ### 🍏 Apple Frameworks Used
228
- | Framework | Purpose |
229
- |-----------|---------|
230
- | MapKit | Maps |
231
- | CoreLocation | GPS |
232
- | AVFoundation | Camera/Audio |
233
-
234
- ### 📱 Native (.dylib) — Investigate
235
- | File | Notes |
236
- |------|-------|
237
- | libcrypto.dylib | Custom crypto? |
238
-
239
- ### ❓ Unknown (investigate)
240
- | Framework/Import | Notes |
241
- |------------------|-------|
242
- | CustomSDK.framework | Proprietary? |
243
- ```
153
+ ## 📋 EXECUTION PIPELINE (v2 — UI-First)
244
154
 
245
- ---
155
+ > **Philosophy:** "Nhìn thấy trước, code logic sau"
156
+ > **Rule:** Always complete one phase fully before moving to the next.
157
+ > **Rule:** UI must be approved before coding logic.
246
158
 
247
- ### Step 1: Info.plist & Entitlements Analysis + Project Bootstrap 📄
248
-
249
- **Input:** User provides `Info.plist` + entitlements from IPA.
250
-
251
- **Tasks:**
252
- 1. Extract Bundle ID and display name
253
- 2. List required permissions (Privacy keys):
254
- ```
255
- NSCameraUsageDescription → Camera
256
- NSPhotoLibraryUsageDescription → Photo Library
257
- NSLocationWhenInUseUsageDescription → Location
258
- NSMicrophoneUsageDescription → Microphone
259
- ```
260
- 3. Identify URL Schemes (deep links)
261
- 4. Check app capabilities from entitlements:
262
- ```
263
- com.apple.developer.associated-domains → Universal Links
264
- aps-environment → Push Notifications
265
- com.apple.developer.in-app-payments → Apple Pay
266
- ```
267
- 5. Analyze class-dump headers for entry points:
268
- - `AppDelegate` → lifecycle logic
269
- - Root ViewController → initial screen
270
- - Tab bar / Navigation structure
271
- 6. **Output:** Propose Clean Architecture project structure
272
-
273
- **Project Structure Template:**
274
159
  ```
275
- App/
276
- ├── App.swift # @main entry point
277
- ├── AppDelegate.swift # UIKit lifecycle (if needed for SDKs)
278
- ├── Info.plist
279
- ├── Assets.xcassets/
280
- ├── DI/ # Dependency Injection
281
- └── AppContainer.swift
282
- ├── Data/ # Data Layer
283
- │ ├── Network/
284
- │ │ ├── APIClient.swift # URLSession wrapper
285
- │ │ ├── Endpoints/ # API endpoint definitions
286
- │ │ └── DTOs/ # Codable response models
287
- │ ├── Local/
288
- │ │ ├── SwiftDataModels/ # @Model classes
289
- │ │ ├── KeychainService.swift
290
- │ │ └── UserDefaultsKeys.swift
291
- │ └── Repositories/ # Repository implementations
292
- ├── Domain/ # Domain Layer
293
- │ ├── Models/ # Business models
294
- │ ├── Repositories/ # Repository protocols
295
- │ └── UseCases/
296
- ├── Presentation/ # Presentation Layer
297
- │ ├── Navigation/
298
- │ │ ├── AppNavigation.swift # NavigationStack + routes
299
- │ │ └── Route.swift # Deep link routes
300
- │ ├── Theme/
301
- │ │ ├── AppTheme.swift # Colors, fonts, spacing
302
- │ │ └── Components/ # Reusable SwiftUI components
303
- │ └── Screens/
304
- │ ├── Launch/
305
- │ │ └── LaunchScreen.swift
306
- │ ├── Auth/
307
- │ │ ├── LoginScreen.swift
308
- │ │ └── LoginViewModel.swift
309
- │ ├── Home/
310
- │ │ ├── HomeScreen.swift
311
- │ │ └── HomeViewModel.swift
312
- │ └── ...
313
- ├── Utilities/
314
- │ ├── Extensions/
315
- │ ├── Crypto/ # Encryption/hashing utils
316
- │ └── Helpers/
317
- └── Resources/
318
- ├── Localizable.xcstrings
319
- └── Fonts/
160
+ Phase 0: Discovery → App Map (satellite view)
161
+ Phase 1: Architecture → Layer design + UI-First build order (district view)
162
+ ┌─── Loop per Feature ──────────────────────────────────────┐
163
+ Phase 2: Blueprint + UI → Contracts + Visual UI Shell │
164
+ 🚦 GATE: User approves UI + Contracts │
165
+ Phase 3: Logic Build → Domain → Data → Wire UI↔Logic │
166
+ 📊 CHECKPOINT: Feature complete │
167
+ └─── Repeat for next feature ───────────────────────────────┘
168
+ Phase 4: Final Parity Check
320
169
  ```
321
170
 
322
- ---
323
-
324
- ### Step 2: Data Layer Reconstruction 💾
325
-
326
- **Input:** User provides class-dump headers + Hopper pseudo-code for network/data classes.
327
-
328
- **Tasks:**
329
- 1. **Models:** Convert ObjC interfaces → Swift structs
330
- ```objc
331
- // ObjC header (class-dump)
332
- @interface UserModel : NSObject
333
- @property (nonatomic, copy) NSString *userId;
334
- @property (nonatomic, copy) NSString *fullName;
335
- @property (nonatomic, assign) NSInteger age;
336
- @end
337
- ```
338
- ```swift
339
- // Swift
340
- struct User: Codable, Identifiable {
341
- let id: String
342
- let fullName: String
343
- let age: Int
344
-
345
- enum CodingKeys: String, CodingKey {
346
- case id = "user_id"
347
- case fullName = "full_name"
348
- case age
349
- }
350
- }
351
- ```
352
-
353
- 2. **API Layer:**
354
- - Extract base URL, endpoints, headers from disassembly
355
- - Create async URLSession-based API client:
356
- ```swift
357
- actor APIClient {
358
- private let session: URLSession
359
- private let baseURL: URL
360
-
361
- func request<T: Decodable>(_ endpoint: Endpoint) async throws -> T {
362
- let (data, response) = try await session.data(for: endpoint.urlRequest(baseURL: baseURL))
363
- guard let httpResponse = response as? HTTPURLResponse,
364
- (200...299).contains(httpResponse.statusCode) else {
365
- throw APIError.invalidResponse
366
- }
367
- return try JSONDecoder().decode(T.self, from: data)
368
- }
369
- }
370
- ```
371
-
372
- 3. **Local Storage:**
373
- - CoreData models → SwiftData `@Model` classes
374
- - NSUserDefaults keys → `@AppStorage` or typed UserDefaults wrapper
375
- - Keychain items → KeychainAccess wrapper
376
-
377
- 4. **Repository:**
378
- ```swift
379
- // Domain layer - protocol
380
- protocol UserRepository: Sendable {
381
- func getUser(id: String) async throws -> User
382
- func login(email: String, password: String) async throws -> AuthToken
383
- }
384
-
385
- // Data layer - implementation
386
- final class UserRepositoryImpl: UserRepository {
387
- private let apiClient: APIClient
388
- private let modelContext: ModelContext
389
-
390
- func getUser(id: String) async throws -> User {
391
- // offline-first: check local → fetch remote → cache
392
- }
393
- }
394
- ```
395
-
396
- ---
397
-
398
- ### Step 3: Core Logic & Utils Reconstruction 🧮
399
-
400
- **Input:** Disassembly/pseudo-code for encryption, hashing, custom utils.
401
-
402
- **Tasks:**
403
- 1. Translate ObjC/C crypto logic → Swift
404
- - Use `CryptoKit` for modern crypto (SHA256, AES-GCM, HMAC)
405
- - Use `CommonCrypto` for legacy-compatible (MD5, AES-CBC)
406
- - Preserve exact input/output signatures
407
-
408
- 2. Common ObjC → Swift crypto patterns:
409
- ```objc
410
- // ObjC (class-dump + disassembly)
411
- + (NSString *)md5Hash:(NSString *)input;
412
- + (NSData *)aesEncrypt:(NSData *)data withKey:(NSString *)key;
413
- ```
414
- ```swift
415
- // Swift
416
- import CryptoKit
417
- import CommonCrypto
418
-
419
- enum CryptoUtils {
420
- static func md5Hash(_ input: String) -> String {
421
- let data = Data(input.utf8)
422
- var digest = [UInt8](repeating: 0, count: Int(CC_MD5_DIGEST_LENGTH))
423
- data.withUnsafeBytes { CC_MD5($0.baseAddress, CC_LONG(data.count), &digest) }
424
- return digest.map { String(format: "%02x", $0) }.joined()
425
- }
426
-
427
- static func aesEncrypt(data: Data, key: String) throws -> Data {
428
- // Implement matching original algorithm exactly
429
- }
430
- }
431
- ```
432
-
433
- 3. **Verification:** XCTest unit tests with known input/output pairs
434
-
435
- **Critical Rule:**
436
- > ⚠️ Crypto/hash functions MUST produce identical output to the original app.
437
- > Test with known pairs captured from the running original app.
171
+ ### Reference Files
438
172
 
439
- ---
173
+ Each phase has a detailed instruction file:
174
+ - `phase-0-discovery.md` — Framework scan, plist analysis, app map
175
+ - `phase-1-architecture.md` — Layer design, feature mapping, build order
176
+ - `phase-2-blueprint-ui.md` — Contracts + UI visual shell + parity check
177
+ - `phase-3-logic-build.md` — Domain, data, DI, ViewModel, wire UI↔logic
440
178
 
441
- ### Step 4: UI & ViewModel Reconstruction (Per Screen) 🎨
442
-
443
- **Input:** Storyboard analysis + class-dump headers for ViewControllers.
444
-
445
- **Tasks:**
446
- 1. **Resource Extraction (On-Demand):**
447
- - Extract only images, colors, strings for current screen
448
- - Use Asset Catalog for organized resources
449
- - Map ObjC string tables to `Localizable.xcstrings`
450
-
451
- 2. **UIKit → SwiftUI Migration:**
452
- ```
453
- UIViewController → SwiftUI View struct
454
- UINavigationController → NavigationStack
455
- UITabBarController → TabView
456
- UITableView → List / LazyVStack
457
- UICollectionView → LazyVGrid / LazyHGrid
458
- UIScrollView → ScrollView
459
- UIImageView → AsyncImage / Image
460
- UILabel → Text
461
- UITextField → TextField
462
- UIButton → Button
463
- UIActivityIndicatorView → ProgressView
464
- UIAlertController → .alert / .confirmationDialog modifier
465
- UIPageViewController → TabView(.page)
466
- UIStackView → VStack / HStack
467
- MKMapView → Map (MapKit SwiftUI)
468
- WKWebView → WebView (custom wrapper)
469
- UIRefreshControl → .refreshable modifier
470
- UISearchController → .searchable modifier
471
- ```
472
-
473
- 3. **ViewModel Creation:**
474
- ```swift
475
- @Observable
476
- final class LoginViewModel {
477
- var email = ""
478
- var password = ""
479
- var isLoading = false
480
- var error: String?
481
-
482
- private let loginUseCase: LoginUseCase
483
-
484
- init(loginUseCase: LoginUseCase) {
485
- self.loginUseCase = loginUseCase
486
- }
487
-
488
- func login() async {
489
- isLoading = true
490
- defer { isLoading = false }
491
- do {
492
- try await loginUseCase.execute(email: email, password: password)
493
- } catch {
494
- self.error = error.localizedDescription
495
- }
496
- }
497
- }
498
- ```
499
-
500
- 4. **Screen Composable:**
501
- ```swift
502
- struct LoginScreen: View {
503
- @State private var viewModel: LoginViewModel
504
-
505
- init(loginUseCase: LoginUseCase) {
506
- _viewModel = State(initialValue: LoginViewModel(loginUseCase: loginUseCase))
507
- }
508
-
509
- var body: some View {
510
- Form {
511
- TextField("Email", text: $viewModel.email)
512
- .textContentType(.emailAddress)
513
- .keyboardType(.emailAddress)
514
-
515
- SecureField("Password", text: $viewModel.password)
516
- .textContentType(.password)
517
-
518
- Button("Login") {
519
- Task { await viewModel.login() }
520
- }
521
- .disabled(viewModel.isLoading)
522
- }
523
- .overlay { if viewModel.isLoading { ProgressView() } }
524
- .alert("Error", isPresented: .constant(viewModel.error != nil)) {
525
- Button("OK") { viewModel.error = nil }
526
- } message: {
527
- Text(viewModel.error ?? "")
528
- }
529
- }
530
- }
531
- ```
179
+ ### Supporting Files
180
+ - `objc-reading-guide.md` — How to read ObjC class-dump headers
181
+ - `framework-patterns.md` Common iOS framework detection patterns
532
182
 
533
183
  ---
534
184
 
535
- ### Step 5: Third-party SDK & Native Library Integration 📦
536
-
537
- **Input:** Framework Report from Step 0.
538
-
539
- **Tasks:**
540
- 1. **Swift Package Manager setup:**
541
- ```swift
542
- // Package.swift dependencies (or Xcode SPM UI)
543
- dependencies: [
544
- .package(url: "https://github.com/firebase/firebase-ios-sdk", from: "11.0.0"),
545
- .package(url: "https://github.com/onevcat/Kingfisher", from: "7.12.0"),
546
- .package(url: "https://github.com/kishikawakatsumi/KeychainAccess", from: "4.2.2"),
547
- ]
548
- ```
549
-
550
- 2. **Native C/C++ libraries:**
551
- ```swift
552
- // Bridging header for C libraries
553
- // App-Bridging-Header.h
554
- #include "native_crypto.h"
555
-
556
- // Swift usage
557
- func callNativeFunction() -> String {
558
- let result = native_function_name(param)
559
- return String(cString: result)
560
- }
561
- ```
562
-
563
- 3. **App lifecycle for SDK init:**
564
- ```swift
565
- @main
566
- struct MyApp: App {
567
- @UIApplicationDelegateAdaptor private var appDelegate: AppDelegate
568
-
569
- var body: some Scene {
570
- WindowGroup {
571
- ContentView()
572
- }
573
- }
574
- }
575
-
576
- class AppDelegate: NSObject, UIApplicationDelegate {
577
- func application(_ application: UIApplication,
578
- didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
579
- FirebaseApp.configure()
580
- // Other SDK initialization
581
- return true
582
- }
583
- }
584
- ```
585
-
586
- ---
587
-
588
- ### Step 6: Parity Check & Quality Gate ✅
589
-
590
- **Per-module checklist:**
591
- 1. **Branch Coverage:** Review all conditional paths from disassembly
592
- 2. **API Parity:** Same requests/responses as original
593
- 3. **Data Parity:** Crypto output matches, local storage compatible
594
- 4. **UI Parity:** Screen-by-screen comparison
595
- 5. **Performance:**
596
- - Instruments profiling
597
- - No unnecessary @State re-renders
598
- - Proper actor isolation (no data races)
599
-
600
- ---
601
-
602
- ## 🔍 ObjC HEADER READING GUIDE
603
-
604
- ### Property Types → Swift
605
- ```objc
606
- @property (nonatomic, copy) NSString *name; // → let name: String
607
- @property (nonatomic, strong) NSArray *items; // → let items: [Any] (refine type)
608
- @property (nonatomic, assign) BOOL isActive; // → let isActive: Bool
609
- @property (nonatomic, assign) NSInteger count; // → let count: Int
610
- @property (nonatomic, assign) CGFloat height; // → let height: CGFloat
611
- @property (nonatomic, strong) NSDictionary *meta; // → let meta: [String: Any]
612
- @property (nonatomic, strong) NSDate *createdAt; // → let createdAt: Date
613
- @property (nonatomic, strong) NSURL *imageURL; // → let imageURL: URL?
614
- @property (nonatomic, strong) NSData *data; // → let data: Data
615
- @property (nullable, nonatomic, copy) NSString *bio; // → let bio: String?
616
- ```
617
-
618
- ### Method Signatures → Swift
619
- ```objc
620
- - (void)fetchUserWithId:(NSString *)userId completion:(void (^)(UserModel *, NSError *))completion;
621
- // → func fetchUser(id: String) async throws -> User
622
-
623
- + (instancetype)sharedInstance;
624
- // → static let shared = ClassName()
625
-
626
- - (BOOL)validateEmail:(NSString *)email;
627
- // → func validateEmail(_ email: String) -> Bool
628
- ```
185
+ ## 🔑 KEY DIFFERENCES FROM v1
629
186
 
630
- ### Delegate Patterns Swift
631
- ```objc
632
- @protocol UserServiceDelegate <NSObject>
633
- - (void)userServiceDidFetchUser:(UserModel *)user;
634
- - (void)userServiceDidFailWithError:(NSError *)error;
635
- @end
636
- ```
637
- ```swift
638
- // Replace with async/await:
639
- func fetchUser() async throws -> User
640
- // Or AsyncStream for multiple values:
641
- func userUpdates() -> AsyncStream<User>
642
- ```
643
-
644
- ### Blocks → Closures / async
645
- ```objc
646
- typedef void (^CompletionHandler)(NSData * _Nullable data, NSError * _Nullable error);
647
- - (void)requestWithCompletion:(CompletionHandler)completion;
648
- ```
649
- ```swift
650
- // Modern Swift: drop the callback, use async
651
- func request() async throws -> Data
652
- ```
187
+ | Aspect | v1 (Old) | v2 (UI-First) |
188
+ |--------|----------|---------------|
189
+ | **Pipeline** | 6-step linear | 4-phase with feature loop |
190
+ | **UI coded when** | Last (Step 4) | Early (Phase 2, before logic) |
191
+ | **Resource extraction** | Last (Step 4.1) | Early (Phase 2.7, before UI code) |
192
+ | **Visual parity check** | End only (Step 6) | Mid-pipeline (Phase 2.9) + Final |
193
+ | **Gate between UI/Logic** | None | Mandatory — user approves UI first |
194
+ | **Preview** | None | Full #Preview for all states |
195
+ | **User feedback** | 1 time (end) | 2 times (UI gate + final check) |
196
+ | **Rework risk** | High | Low (UI locked before logic) |
653
197
 
654
198
  ---
655
199
 
@@ -658,12 +202,12 @@ func request() async throws -> Data
658
202
  ```yaml
659
203
  triggers_from:
660
204
  - "/reverse-ios" workflow command
661
- - Keywords: "ipa", "class-dump", "objc to swift", "dịch ngược ios", "reverse ios"
205
+ - Keywords: "ipa", "class-dump", "objc to swift", "dịch ngược ios"
662
206
 
663
207
  delegates_to:
664
208
  - "/test" — after parity check
665
209
  - "/deploy" — when rebuild is complete
666
- - beads-manager — auto-track progress per step
210
+ - beads-manager — auto-track progress per phase
667
211
 
668
212
  works_with:
669
213
  - memory-sync — saves decisions, patterns, solutions
@@ -675,41 +219,58 @@ independent_from:
675
219
  - smali-to-kotlin (sibling, same pattern, different platform)
676
220
  ```
677
221
 
222
+ ### Session State Tracking
223
+
224
+ ```yaml
225
+ session_state:
226
+ current_phase: 0-4
227
+ current_feature: "Auth"
228
+ phase_2_status:
229
+ contracts: approved | pending
230
+ ui_shell: approved | pending
231
+ resources: extracted | pending
232
+ completed_features: ["Launch", "Login"]
233
+ pending_features: ["Home", "Settings"]
234
+ ```
235
+
678
236
  ---
679
237
 
680
238
  ## 🚫 ANTI-PATTERNS
681
239
 
682
240
  ```yaml
683
241
  never_do:
684
- - Copy all resources blindly from IPA → only on-demand
242
+ - Copy all resources blindly from IPA → only on-demand per screen
243
+ - Skip Phase 2 UI gate → jump to logic coding
244
+ - Code ViewModel before UI is approved → UI design might change
245
+ - Modify UI shell significantly in Phase 3 → only wire, don't redesign
685
246
  - Use UIKit when SwiftUI equivalent exists → always prefer SwiftUI
686
- - Use GCD dispatch_async for new code → use async/await
687
- - Use NSJSONSerialization → use Codable
247
+ - Use GCD for new code → use async/await
688
248
  - Modify encryption output → must match original exactly
689
- - Create massive ViewController God objects → split into SwiftUI Views + ViewModels
249
+ - Create massive ViewController God objects → split into Views + ViewModels
690
250
  - Skip framework scanner step → always detect reusable dependencies first
691
- - Use ObjC in new code → Swift only (except bridging headers for C libs)
251
+ - Use ObjC in new code → Swift only (except bridging headers)
692
252
  - Force unwrap optionals → use guard let / if let / nil coalescing
693
253
 
694
254
  always_do:
695
- - Run Framework Scanner (Step 0) before any coding
696
- - Present framework report to user for approval
255
+ - Run Framework Scanner (Phase 0) before any coding
256
+ - Extract resources BEFORE coding UI (2.7 → 2.8)
257
+ - Create #Preview for ALL states (normal, loading, error, empty)
258
+ - Get user approval on UI before coding logic
259
+ - Keep stateless View for Preview even after wiring
697
260
  - Use Swift Concurrency (async/await) for all async operations
698
261
  - Use @Observable (iOS 17+) for ViewModels
699
- - Use NavigationStack for navigation
700
- - Unit test all encryption/hashing utils
701
- - Follow Clean Architecture layer separation strictly
702
262
  - Use SPM for dependency management (not CocoaPods)
263
+ - Unit test all encryption/hashing utils
703
264
  ```
704
265
 
705
266
  ---
706
267
 
707
268
  ## 📊 CHECKPOINT TEMPLATE
708
269
 
709
- After each step, output:
270
+ After each phase/feature, output:
710
271
 
711
272
  ```markdown
712
- ## ✅ Step [N] Complete: [Step Name]
273
+ ## ✅ [Phase/Feature] Complete: [Name]
713
274
 
714
275
  ### What was done:
715
276
  - [Summary]
@@ -723,7 +284,7 @@ After each step, output:
723
284
  ### Decisions made:
724
285
  - [Key decisions]
725
286
 
726
- ### ⏭️ Next: Step [N+1] — [Step Name]
287
+ ### ⏭️ Next: [Phase/Feature] — [Name]
727
288
  - [What user needs to provide]
728
289
  ```
729
290
 
@@ -731,19 +292,17 @@ After each step, output:
731
292
 
732
293
  ## 🧩 PLATFORM RE TEMPLATE PATTERN
733
294
 
734
- This skill follows the same **6-step pipeline** as `smali-to-kotlin`:
295
+ This skill follows the same **4-phase pipeline** as `smali-to-kotlin`:
735
296
 
736
- | Step | Android (smali-to-kotlin) | iOS (smali-to-swift) |
737
- |------|--------------------------|---------------------|
297
+ | Phase | Android (smali-to-kotlin) | iOS (smali-to-swift) |
298
+ |-------|--------------------------|---------------------|
738
299
  | 0 | Library Scanner (Smali packages) | Framework Scanner (Frameworks/ + headers) |
739
- | 1 | AndroidManifest.xml | Info.plist + Entitlements |
740
- | 2 | Retrofit + Room | URLSession + SwiftData |
741
- | 3 | Kotlin crypto utils | Swift CryptoKit/CommonCrypto |
742
- | 4 | Jetpack Compose + StateFlow | SwiftUI + @Observable |
743
- | 5 | Hilt + JNI | SPM + Bridging Header |
744
- | 6 | Parity Check | Parity Check |
300
+ | 1 | AndroidManifest → Architecture | Info.plist Architecture |
301
+ | 2 | Contracts + Compose UI Shell | Contracts + SwiftUI Shell |
302
+ | 3 | Domain + Data + Wire Compose | Domain + Data + Wire SwiftUI |
303
+ | 4 | Parity Check | Parity Check |
745
304
 
746
305
  ---
747
306
 
748
- *smali-to-swift v1.0.0 — iOS Reverse Engineering Skill for AWF*
307
+ *smali-to-swift v2.0.0 — UI-First iOS Reverse Engineering Skill*
749
308
  *Created by Antigravity Team*