@buivietphi/skill-mobile-mt 1.0.0

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.
@@ -0,0 +1,182 @@
1
+ # iOS Native — Production Patterns
2
+
3
+ > Battle-tested patterns for iOS Swift development.
4
+ > Also used as reference for RN/Flutter iOS native module issues.
5
+
6
+ ---
7
+
8
+ ## Clean Architecture
9
+
10
+ ```
11
+ ProjectName/
12
+ ├── ProjectName.xcodeproj
13
+ ├── ProjectName.xcworkspace # CocoaPods workspace
14
+ ├── Podfile # CocoaPods deps
15
+ ├── Gemfile # Ruby deps for CocoaPods
16
+ ├── ProjectName/
17
+ │ ├── App/
18
+ │ │ ├── AppDelegate.swift # Or @main App struct
19
+ │ │ └── SceneDelegate.swift
20
+ │ ├── Domain/ # Business logic (pure)
21
+ │ │ ├── Entities/ # Core business models
22
+ │ │ ├── UseCases/ # Business rules
23
+ │ │ └── Repositories/ # Repository protocols (contracts)
24
+ │ ├── Data/ # Data layer (implements Domain)
25
+ │ │ ├── Repositories/ # Repository implementations
26
+ │ │ ├── Network/ # APIClient, endpoints
27
+ │ │ ├── Storage/ # KeychainManager, CoreData
28
+ │ │ └── DTOs/ # Data transfer objects + mappers
29
+ │ ├── Presentation/ # UI layer
30
+ │ │ ├── Features/
31
+ │ │ │ ├── Auth/
32
+ │ │ │ │ ├── Views/
33
+ │ │ │ │ └── ViewModels/
34
+ │ │ │ └── [Feature]/
35
+ │ │ └── Shared/
36
+ │ │ ├── Components/
37
+ │ │ └── Utils/
38
+ │ └── Resources/
39
+ │ ├── Assets.xcassets
40
+ │ └── Info.plist
41
+ └── Pods/ # CocoaPods output
42
+ ```
43
+
44
+ ### Dependency Rule
45
+ ```
46
+ Presentation/ → Domain/ ← Data/
47
+
48
+ Views and ViewModels depend on Domain.
49
+ Data layer implements Domain protocols.
50
+ Domain depends on NOTHING.
51
+ ```
52
+
53
+ ## SwiftUI View + ViewModel (MVVM)
54
+
55
+ ```swift
56
+ struct ProductListView: View {
57
+ @StateObject private var viewModel = ProductListViewModel()
58
+
59
+ var body: some View {
60
+ NavigationStack {
61
+ content
62
+ .navigationTitle("Products")
63
+ .refreshable { await viewModel.refresh() }
64
+ }
65
+ .task { await viewModel.loadIfNeeded() }
66
+ }
67
+
68
+ @ViewBuilder
69
+ private var content: some View {
70
+ switch viewModel.state {
71
+ case .loading: ProgressView()
72
+ case .loaded(let items) where items.isEmpty:
73
+ ContentUnavailableView("No Items", systemImage: "tray")
74
+ case .loaded(let items):
75
+ List(items) { item in
76
+ NavigationLink(value: item) { ItemRow(item: item) }
77
+ }
78
+ case .error(let error):
79
+ ContentUnavailableView {
80
+ Label("Error", systemImage: "exclamationmark.triangle")
81
+ } description: { Text(error.localizedDescription) }
82
+ actions: { Button("Retry") { Task { await viewModel.refresh() } } }
83
+ }
84
+ }
85
+ }
86
+
87
+ @MainActor
88
+ final class ProductListViewModel: ObservableObject {
89
+ enum State { case loading, loaded([Product]), error(Error) }
90
+ @Published private(set) var state: State = .loading
91
+
92
+ private let useCase: GetProductsUseCase
93
+ init(useCase: GetProductsUseCase = GetProductsUseCaseImpl()) { self.useCase = useCase }
94
+
95
+ func loadIfNeeded() async {
96
+ guard case .loading = state else { return }
97
+ await refresh()
98
+ }
99
+
100
+ func refresh() async {
101
+ state = .loading
102
+ do { state = .loaded(try await useCase.execute()) }
103
+ catch { state = .error(error) }
104
+ }
105
+ }
106
+ ```
107
+
108
+ ## Networking
109
+
110
+ ```swift
111
+ actor APIClient {
112
+ func request<T: Decodable>(_ endpoint: Endpoint, as: T.Type) async throws -> T {
113
+ var req = endpoint.urlRequest(baseURL: baseURL)
114
+ if endpoint.requiresAuth {
115
+ req.setValue("Bearer \(try await tokenProvider.token())", forHTTPHeaderField: "Authorization")
116
+ }
117
+ let (data, response) = try await URLSession.shared.data(for: req)
118
+ guard let http = response as? HTTPURLResponse, (200...299).contains(http.statusCode) else {
119
+ throw APIError.from(response: response as? HTTPURLResponse)
120
+ }
121
+ return try JSONDecoder().decode(T.self, from: data)
122
+ }
123
+ }
124
+ ```
125
+
126
+ ## Keychain Storage
127
+
128
+ ```swift
129
+ final class KeychainManager {
130
+ static let shared = KeychainManager()
131
+ func save(_ data: Data, for key: String) throws {
132
+ let query: [CFString: Any] = [
133
+ kSecClass: kSecClassGenericPassword, kSecAttrAccount: key,
134
+ kSecValueData: data, kSecAttrAccessible: kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly,
135
+ ]
136
+ SecItemDelete(query as CFDictionary)
137
+ guard SecItemAdd(query as CFDictionary, nil) == errSecSuccess else { throw KeychainError.saveFailed }
138
+ }
139
+ func load(for key: String) -> Data? {
140
+ let query: [CFString: Any] = [
141
+ kSecClass: kSecClassGenericPassword, kSecAttrAccount: key,
142
+ kSecReturnData: true, kSecMatchLimit: kSecMatchLimitOne,
143
+ ]
144
+ var result: AnyObject?
145
+ return SecItemCopyMatching(query as CFDictionary, &result) == errSecSuccess ? result as? Data : nil
146
+ }
147
+ }
148
+ ```
149
+
150
+ ## CocoaPods
151
+
152
+ ```ruby
153
+ # Podfile
154
+ platform :ios, '15.0'
155
+ use_frameworks!
156
+
157
+ target 'ProjectName' do
158
+ pod 'Alamofire'
159
+ pod 'Kingfisher'
160
+ pod 'SnapKit'
161
+ end
162
+ ```
163
+
164
+ ```bash
165
+ cd ios && pod install
166
+ bundle exec pod install # If using Bundler
167
+ ```
168
+
169
+ ## Common Pitfalls
170
+
171
+ | Pitfall | Fix |
172
+ |---------|-----|
173
+ | Force unwrap `!` | `guard let` / `??` |
174
+ | Retain cycles | `[weak self]` in closures |
175
+ | Main thread violation | `@MainActor` |
176
+ | `NavigationView` deprecated | `NavigationStack` |
177
+ | Hardcoded colors | Semantic: `Color(.label)` |
178
+
179
+ ---
180
+
181
+ > No force unwraps. No retain cycles. `@MainActor` for all UI state.
182
+ > MVVM + Clean Architecture. Protocols for testability.
package/package.json ADDED
@@ -0,0 +1,50 @@
1
+ {
2
+ "name": "@buivietphi/skill-mobile-mt",
3
+ "version": "1.0.0",
4
+ "description": "Master Senior Mobile Engineer skill for AI agents. Pre-built patterns from 18 production apps + local project adaptation. React Native, Flutter, iOS, Android. Supports Claude, Gemini, Kimi, Cursor, Copilot, Antigravity.",
5
+ "author": "buivietphi",
6
+ "license": "MIT",
7
+ "keywords": [
8
+ "claude-code",
9
+ "gemini",
10
+ "kimi",
11
+ "antigravity",
12
+ "cursor",
13
+ "agent-skills",
14
+ "mobile",
15
+ "react-native",
16
+ "flutter",
17
+ "ios",
18
+ "android",
19
+ "clean-architecture",
20
+ "code-review",
21
+ "prompt-engineering"
22
+ ],
23
+ "bin": {
24
+ "skill-mobile": "bin/install.mjs"
25
+ },
26
+ "files": [
27
+ "bin/",
28
+ "SKILL.md",
29
+ "AGENTS.md",
30
+ "react-native/",
31
+ "flutter/",
32
+ "ios/",
33
+ "android/",
34
+ "shared/"
35
+ ],
36
+ "scripts": {
37
+ "postinstall": "node bin/install.mjs --auto",
38
+ "install:claude": "node bin/install.mjs --claude",
39
+ "install:gemini": "node bin/install.mjs --gemini",
40
+ "install:kimi": "node bin/install.mjs --kimi",
41
+ "install:all": "node bin/install.mjs --all"
42
+ },
43
+ "engines": {
44
+ "node": ">=18"
45
+ },
46
+ "repository": {
47
+ "type": "git",
48
+ "url": "https://github.com/buivietphi/skill-mobile-mt"
49
+ }
50
+ }