@buivietphi/skill-mobile-mt 1.4.2 → 1.4.3
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.
Potentially problematic release.
This version of @buivietphi/skill-mobile-mt might be problematic. Click here for more details.
- package/AGENTS.md +9 -9
- package/README.md +82 -66
- package/SKILL.md +1 -1
- package/android/android-native.md +222 -0
- package/bin/install.mjs +1 -1
- package/package.json +2 -2
package/AGENTS.md
CHANGED
|
@@ -40,7 +40,7 @@ skill-mobile-mt/
|
|
|
40
40
|
│ └── ios-native.md ← Swift + UIKit/SwiftUI patterns (1,452 tokens)
|
|
41
41
|
│
|
|
42
42
|
├── android/
|
|
43
|
-
│ └── android-native.md ← Kotlin + Compose patterns (
|
|
43
|
+
│ └── android-native.md ← Kotlin + Compose + Java legacy patterns (4,400 tokens)
|
|
44
44
|
│
|
|
45
45
|
└── shared/
|
|
46
46
|
│
|
|
@@ -71,8 +71,8 @@ skill-mobile-mt/
|
|
|
71
71
|
```
|
|
72
72
|
|
|
73
73
|
**Token totals:**
|
|
74
|
-
- Smart load (1 platform + core shared): **~
|
|
75
|
-
- Full load (all files): **~
|
|
74
|
+
- Smart load (1 platform + core shared): **~40,900 tokens** (31.9% of 128K)
|
|
75
|
+
- Full load (all files): **~77,000 tokens** (60.2% of 128K)
|
|
76
76
|
|
|
77
77
|
---
|
|
78
78
|
|
|
@@ -122,7 +122,7 @@ The agent reads the task, then decides which extra file to load:
|
|
|
122
122
|
|
|
123
123
|
**No automatic trigger.** Full load happens when the AI reads every file without being selective — either because it's over-eager, or because the user explicitly asks for it.
|
|
124
124
|
|
|
125
|
-
**Total:** ~
|
|
125
|
+
**Total:** ~72,300 tokens (56.5% of 128K, 36% of 200K)
|
|
126
126
|
|
|
127
127
|
**How it actually works:**
|
|
128
128
|
- `@skill-mobile-mt` only injects SKILL.md into context
|
|
@@ -214,9 +214,9 @@ skill:
|
|
|
214
214
|
java: ".java files in app/src/"
|
|
215
215
|
|
|
216
216
|
context_budget:
|
|
217
|
-
max_tokens:
|
|
218
|
-
smart_load_tokens:
|
|
219
|
-
savings: "~
|
|
217
|
+
max_tokens: 77000
|
|
218
|
+
smart_load_tokens: 40900
|
|
219
|
+
savings: "~47%"
|
|
220
220
|
```
|
|
221
221
|
|
|
222
222
|
---
|
|
@@ -463,10 +463,10 @@ npx @buivietphi/skill-mobile-mt --init all # → all files
|
|
|
463
463
|
{
|
|
464
464
|
"id": "skill-mobile-mt",
|
|
465
465
|
"name": "skill-mobile-mt",
|
|
466
|
-
"version": "1.4.
|
|
466
|
+
"version": "1.4.3",
|
|
467
467
|
"author": "buivietphi",
|
|
468
468
|
"category": "engineering",
|
|
469
|
-
"description": "Master Senior Mobile Engineer. Pre-built patterns from
|
|
469
|
+
"description": "Master Senior Mobile Engineer. Pre-built patterns from 30+ production repos + project adaptation. Auto-detects language and framework. React Native, Flutter, iOS, Android.",
|
|
470
470
|
"risk": "low",
|
|
471
471
|
"source": "buivietphi (MIT)",
|
|
472
472
|
"platforms": ["react-native", "flutter", "ios", "android"],
|
package/README.md
CHANGED
|
@@ -72,6 +72,73 @@ Reads your current project first, then follows **your** conventions:
|
|
|
72
72
|
- Clones the most similar existing feature when scaffolding new ones
|
|
73
73
|
- Never suggests migrations or imposes different architecture
|
|
74
74
|
|
|
75
|
+
## Humanizer — Mobile Copy
|
|
76
|
+
|
|
77
|
+
Installed automatically alongside the main skill. Removes AI writing patterns from mobile app text.
|
|
78
|
+
|
|
79
|
+
```
|
|
80
|
+
@humanizer-mobile
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Use for: app store descriptions, release notes, error messages, onboarding, push notifications, permission prompts, paywall copy.
|
|
84
|
+
|
|
85
|
+
**App Store Description**
|
|
86
|
+
```
|
|
87
|
+
❌ "TaskFlow is a powerful, comprehensive task management application that
|
|
88
|
+
seamlessly integrates with your existing workflow."
|
|
89
|
+
|
|
90
|
+
✅ "TaskFlow keeps your team's work in one place. Add tasks, assign them,
|
|
91
|
+
set deadlines — everything syncs in real time. Works with Slack and Notion."
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
**Release Notes**
|
|
95
|
+
```
|
|
96
|
+
❌ "Version 2.1.0 introduces significant enhancements to the overall user
|
|
97
|
+
experience including robust improvements to performance and reliability."
|
|
98
|
+
|
|
99
|
+
✅ "2.1.0
|
|
100
|
+
- Faster load times on older Android devices (was 4s, now 1.2s)
|
|
101
|
+
- Fixed crash when opening notifications while offline
|
|
102
|
+
- Dark mode now remembers your setting between sessions"
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
**Error Messages**
|
|
106
|
+
```
|
|
107
|
+
❌ "We apologize for the inconvenience. An unexpected error has occurred."
|
|
108
|
+
|
|
109
|
+
✅ "Couldn't save — no internet connection.
|
|
110
|
+
[Try again] [Save for later]"
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
**Push Notifications**
|
|
114
|
+
```
|
|
115
|
+
❌ "You have received a new message from a team member."
|
|
116
|
+
✅ "Alex commented on "Landing page redesign""
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
**Paywall**
|
|
120
|
+
```
|
|
121
|
+
❌ "Unlock the full potential of our comprehensive premium features."
|
|
122
|
+
|
|
123
|
+
✅ "Go Pro
|
|
124
|
+
• Unlimited projects (free plan: 3)
|
|
125
|
+
• Team sharing
|
|
126
|
+
[Start 7-day free trial]"
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Covers 24 AI patterns across: content inflation, chatbot artifacts, style issues, mobile-specific copy (App Store limits, permission prompts, rating requests, subscription CTAs).
|
|
130
|
+
|
|
131
|
+
### Works with all agents
|
|
132
|
+
|
|
133
|
+
| Agent | Invocation |
|
|
134
|
+
|-------|-----------|
|
|
135
|
+
| Claude Code | `@humanizer-mobile` |
|
|
136
|
+
| Gemini CLI | `@humanizer-mobile` |
|
|
137
|
+
| Codex / Kimi / Antigravity | `@humanizer-mobile` |
|
|
138
|
+
| Cline / Roo Code / Cursor / Windsurf / Copilot | Paste the text and say "humanize this app copy" |
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
75
142
|
## Quick Start Examples
|
|
76
143
|
|
|
77
144
|
### Step 1: Install the skill
|
|
@@ -101,6 +168,15 @@ You'll see an interactive checkbox — use arrow keys to navigate, space to sele
|
|
|
101
168
|
◯ Antigravity [not found]
|
|
102
169
|
```
|
|
103
170
|
|
|
171
|
+
Install output:
|
|
172
|
+
|
|
173
|
+
```
|
|
174
|
+
✓ skill-mobile-mt/ → Claude Code (~/.claude/skills/skill-mobile-mt)
|
|
175
|
+
✓ humanizer-mobile/ → Claude Code (~/.claude/skills/humanizer-mobile)
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
Both are installed automatically. Use `@humanizer-mobile` for app store copy, release notes, and UX text.
|
|
179
|
+
|
|
104
180
|
### Step 2: Generate project rules
|
|
105
181
|
|
|
106
182
|
```bash
|
|
@@ -231,9 +307,9 @@ iOS only?
|
|
|
231
307
|
|----------|-------:|----------:|----------:|
|
|
232
308
|
| SKILL.md only | ~13,200 | 10.3% | 6.6% |
|
|
233
309
|
| + 1 platform + core shared/ | ~38,600 | 30.2% | 19.3% |
|
|
234
|
-
| Cross-platform (RN/Flutter + iOS + Android) | ~
|
|
235
|
-
| All files loaded | ~
|
|
236
|
-
| **Smart load (recommended)** | **~
|
|
310
|
+
| Cross-platform (RN/Flutter + iOS + Android) | ~55,300 | 43.2% | 27.7% |
|
|
311
|
+
| All files loaded | ~77,000 | 60.2% | 38.5% |
|
|
312
|
+
| **Smart load (recommended)** | **~40,900** | **31.9%** | **20.5%** |
|
|
237
313
|
|
|
238
314
|
### Per-file token breakdown
|
|
239
315
|
|
|
@@ -244,7 +320,7 @@ iOS only?
|
|
|
244
320
|
| `react-native/react-native.md` | 5,108 |
|
|
245
321
|
| `flutter/flutter.md` | 2,100 |
|
|
246
322
|
| `ios/ios-native.md` | 1,452 |
|
|
247
|
-
| `android/android-native.md` |
|
|
323
|
+
| `android/android-native.md` | 4,400 |
|
|
248
324
|
| `shared/code-review.md` | 865 |
|
|
249
325
|
| `shared/bug-detection.md` | 499 |
|
|
250
326
|
| `shared/prompt-engineering.md` | 3,927 |
|
|
@@ -263,7 +339,7 @@ iOS only?
|
|
|
263
339
|
| `shared/ci-cd.md` | 2,500 |
|
|
264
340
|
| `shared/claude-md-template.md` | ~500 |
|
|
265
341
|
| `shared/agent-rules-template.md` | ~2,500 |
|
|
266
|
-
| **Total** | **~
|
|
342
|
+
| **Total** | **~55,800** |
|
|
267
343
|
|
|
268
344
|
## Installed Structure
|
|
269
345
|
|
|
@@ -279,7 +355,7 @@ iOS only?
|
|
|
279
355
|
├── ios/
|
|
280
356
|
│ └── ios-native.md iOS Swift patterns
|
|
281
357
|
├── android/
|
|
282
|
-
│ └── android-native.md Android Kotlin patterns
|
|
358
|
+
│ └── android-native.md Android Kotlin + Java patterns
|
|
283
359
|
└── shared/
|
|
284
360
|
├── code-review.md Senior review checklist
|
|
285
361
|
├── bug-detection.md Auto bug scanner
|
|
@@ -427,66 +503,6 @@ your-project/
|
|
|
427
503
|
| **Kiro** | Reads `.kiro/steering/` from project root | `npx skill-mobile-mt --init kiro` |
|
|
428
504
|
| **Antigravity** | Reads from `~/.agents/skills/` | `npx skill-mobile-mt --antigravity` |
|
|
429
505
|
|
|
430
|
-
## Humanizer — Mobile Copy
|
|
431
|
-
|
|
432
|
-
Installed automatically alongside the main skill. Removes AI writing patterns from mobile app text.
|
|
433
|
-
|
|
434
|
-
```
|
|
435
|
-
@humanizer-mobile
|
|
436
|
-
```
|
|
437
|
-
|
|
438
|
-
Use for: app store descriptions, release notes, error messages, onboarding, push notifications, permission prompts, paywall copy.
|
|
439
|
-
|
|
440
|
-
### Examples
|
|
441
|
-
|
|
442
|
-
**App Store Description**
|
|
443
|
-
```
|
|
444
|
-
❌ "TaskFlow is a powerful, comprehensive task management application that
|
|
445
|
-
seamlessly integrates with your existing workflow."
|
|
446
|
-
|
|
447
|
-
✅ "TaskFlow keeps your team's work in one place. Add tasks, assign them,
|
|
448
|
-
set deadlines — everything syncs in real time. Works with Slack and Notion."
|
|
449
|
-
```
|
|
450
|
-
|
|
451
|
-
**Release Notes**
|
|
452
|
-
```
|
|
453
|
-
❌ "Version 2.1.0 introduces significant enhancements to the overall user
|
|
454
|
-
experience including robust improvements to performance and reliability."
|
|
455
|
-
|
|
456
|
-
✅ "2.1.0
|
|
457
|
-
- Faster load times on older Android devices (was 4s, now 1.2s)
|
|
458
|
-
- Fixed crash when opening notifications while offline
|
|
459
|
-
- Dark mode now remembers your setting between sessions"
|
|
460
|
-
```
|
|
461
|
-
|
|
462
|
-
**Error Messages**
|
|
463
|
-
```
|
|
464
|
-
❌ "We apologize for the inconvenience. An unexpected error has occurred."
|
|
465
|
-
|
|
466
|
-
✅ "Couldn't save — no internet connection.
|
|
467
|
-
[Try again] [Save for later]"
|
|
468
|
-
```
|
|
469
|
-
|
|
470
|
-
**Push Notifications**
|
|
471
|
-
```
|
|
472
|
-
❌ "You have received a new message from a team member."
|
|
473
|
-
✅ "Alex commented on "Landing page redesign""
|
|
474
|
-
```
|
|
475
|
-
|
|
476
|
-
**Paywall**
|
|
477
|
-
```
|
|
478
|
-
❌ "Unlock the full potential of our comprehensive premium features."
|
|
479
|
-
|
|
480
|
-
✅ "Go Pro
|
|
481
|
-
• Unlimited projects (free plan: 3)
|
|
482
|
-
• Team sharing
|
|
483
|
-
[Start 7-day free trial]"
|
|
484
|
-
```
|
|
485
|
-
|
|
486
|
-
Covers 24 AI patterns across: content inflation, chatbot artifacts, style issues, mobile-specific copy (App Store limits, permission prompts, rating requests, subscription CTAs).
|
|
487
|
-
|
|
488
|
-
---
|
|
489
|
-
|
|
490
506
|
## License
|
|
491
507
|
|
|
492
508
|
MIT — by [buivietphi](https://github.com/buivietphi)
|
package/SKILL.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: skill-mobile-mt
|
|
3
3
|
description: "Master Senior Mobile Engineer. Patterns from 30+ production repos (200k+ GitHub stars: Ignite, Expensify, Mattermost, Immich, AppFlowy, Now in Android, TCA). Use when: building mobile features, fixing mobile bugs, reviewing mobile code, mobile architecture, React Native, Flutter, iOS Swift, Android Kotlin, mobile performance, mobile security audit, mobile code review, app release. Two modes: (1) default = pre-built production patterns, (2) 'project' = reads current project and adapts."
|
|
4
|
-
version: "1.4.
|
|
4
|
+
version: "1.4.3"
|
|
5
5
|
author: buivietphi
|
|
6
6
|
priority: high
|
|
7
7
|
user-invocable: true
|
|
@@ -254,5 +254,227 @@ dependencies {
|
|
|
254
254
|
|
|
255
255
|
---
|
|
256
256
|
|
|
257
|
+
## Java Interop (Legacy Projects)
|
|
258
|
+
|
|
259
|
+
> For projects still using Java. New code should use Kotlin.
|
|
260
|
+
|
|
261
|
+
### Activity + XML Layout (Java)
|
|
262
|
+
|
|
263
|
+
```java
|
|
264
|
+
// MainActivity.java
|
|
265
|
+
@AndroidEntryPoint
|
|
266
|
+
public class MainActivity extends AppCompatActivity {
|
|
267
|
+
|
|
268
|
+
private MainViewModel viewModel;
|
|
269
|
+
private ActivityMainBinding binding;
|
|
270
|
+
|
|
271
|
+
@Override
|
|
272
|
+
protected void onCreate(Bundle savedInstanceState) {
|
|
273
|
+
super.onCreate(savedInstanceState);
|
|
274
|
+
binding = ActivityMainBinding.inflate(getLayoutInflater());
|
|
275
|
+
setContentView(binding.getRoot());
|
|
276
|
+
|
|
277
|
+
viewModel = new ViewModelProvider(this).get(MainViewModel.class);
|
|
278
|
+
|
|
279
|
+
// Observe LiveData (Java equivalent of collectAsStateWithLifecycle)
|
|
280
|
+
viewModel.getUiState().observe(this, state -> {
|
|
281
|
+
if (state instanceof UiState.Loading) {
|
|
282
|
+
binding.progressBar.setVisibility(View.VISIBLE);
|
|
283
|
+
binding.recyclerView.setVisibility(View.GONE);
|
|
284
|
+
} else if (state instanceof UiState.Error) {
|
|
285
|
+
binding.progressBar.setVisibility(View.GONE);
|
|
286
|
+
Toast.makeText(this, ((UiState.Error) state).getMessage(), Toast.LENGTH_SHORT).show();
|
|
287
|
+
} else if (state instanceof UiState.Success) {
|
|
288
|
+
binding.progressBar.setVisibility(View.GONE);
|
|
289
|
+
binding.recyclerView.setVisibility(View.VISIBLE);
|
|
290
|
+
adapter.submitList(((UiState.Success<List<Product>>) state).getData());
|
|
291
|
+
}
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
binding.retryButton.setOnClickListener(v -> viewModel.load());
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
### ViewModel + LiveData (Java)
|
|
300
|
+
|
|
301
|
+
```java
|
|
302
|
+
// ProductListViewModel.java
|
|
303
|
+
@HiltViewModel
|
|
304
|
+
public class ProductListViewModel extends ViewModel {
|
|
305
|
+
|
|
306
|
+
private final MutableLiveData<UiState<List<Product>>> _uiState =
|
|
307
|
+
new MutableLiveData<>(new UiState.Loading<>());
|
|
308
|
+
private final LiveData<UiState<List<Product>>> uiState = _uiState;
|
|
309
|
+
|
|
310
|
+
private final GetProductsUseCase getProducts;
|
|
311
|
+
|
|
312
|
+
@Inject
|
|
313
|
+
public ProductListViewModel(GetProductsUseCase getProducts) {
|
|
314
|
+
this.getProducts = getProducts;
|
|
315
|
+
load();
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
public LiveData<UiState<List<Product>>> getUiState() { return uiState; }
|
|
319
|
+
|
|
320
|
+
public void load() {
|
|
321
|
+
_uiState.setValue(new UiState.Loading<>());
|
|
322
|
+
// Use RxJava or ExecutorService for async in Java
|
|
323
|
+
ExecutorService executor = Executors.newSingleThreadExecutor();
|
|
324
|
+
executor.execute(() -> {
|
|
325
|
+
try {
|
|
326
|
+
List<Product> items = getProducts.executeSync(); // blocking call
|
|
327
|
+
new Handler(Looper.getMainLooper()).post(() -> {
|
|
328
|
+
if (items.isEmpty()) _uiState.setValue(new UiState.Empty<>());
|
|
329
|
+
else _uiState.setValue(new UiState.Success<>(items));
|
|
330
|
+
});
|
|
331
|
+
} catch (Exception e) {
|
|
332
|
+
new Handler(Looper.getMainLooper()).post(() ->
|
|
333
|
+
_uiState.setValue(new UiState.Error<>(e.getMessage()))
|
|
334
|
+
);
|
|
335
|
+
} finally {
|
|
336
|
+
executor.shutdown();
|
|
337
|
+
}
|
|
338
|
+
});
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
### Retrofit + Callback (Java)
|
|
344
|
+
|
|
345
|
+
```java
|
|
346
|
+
// ProductApi.java
|
|
347
|
+
public interface ProductApi {
|
|
348
|
+
@GET("products")
|
|
349
|
+
Call<ApiResponse<List<ProductDto>>> getProducts();
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
// ProductRepositoryImpl.java
|
|
353
|
+
public class ProductRepositoryImpl implements ProductRepository {
|
|
354
|
+
private final ProductApi api;
|
|
355
|
+
private final ProductDao dao;
|
|
356
|
+
|
|
357
|
+
@Inject
|
|
358
|
+
public ProductRepositoryImpl(ProductApi api, ProductDao dao) {
|
|
359
|
+
this.api = api;
|
|
360
|
+
this.dao = dao;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
@Override
|
|
364
|
+
public void getProducts(Callback<List<Product>> callback) {
|
|
365
|
+
api.getProducts().enqueue(new retrofit2.Callback<ApiResponse<List<ProductDto>>>() {
|
|
366
|
+
@Override
|
|
367
|
+
public void onResponse(Call<ApiResponse<List<ProductDto>>> call,
|
|
368
|
+
Response<ApiResponse<List<ProductDto>>> response) {
|
|
369
|
+
if (response.isSuccessful() && response.body() != null) {
|
|
370
|
+
List<Product> items = mapToDomain(response.body().getData());
|
|
371
|
+
callback.onSuccess(items);
|
|
372
|
+
} else {
|
|
373
|
+
callback.onError("Server error: " + response.code());
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
@Override
|
|
378
|
+
public void onFailure(Call<ApiResponse<List<ProductDto>>> call, Throwable t) {
|
|
379
|
+
callback.onError(t.getMessage());
|
|
380
|
+
}
|
|
381
|
+
});
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
### Room DAO (Java)
|
|
387
|
+
|
|
388
|
+
```java
|
|
389
|
+
// ProductDao.java
|
|
390
|
+
@Dao
|
|
391
|
+
public interface ProductDao {
|
|
392
|
+
@Query("SELECT * FROM products")
|
|
393
|
+
LiveData<List<ProductEntity>> getAll(); // LiveData for Java observers
|
|
394
|
+
|
|
395
|
+
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
|
396
|
+
void insertAll(List<ProductEntity> items);
|
|
397
|
+
|
|
398
|
+
@Query("DELETE FROM products")
|
|
399
|
+
void deleteAll();
|
|
400
|
+
}
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
### Java-Kotlin Interop Annotations
|
|
404
|
+
|
|
405
|
+
```kotlin
|
|
406
|
+
// When writing Kotlin code that will be called from Java:
|
|
407
|
+
|
|
408
|
+
// @JvmStatic — allows calling companion object functions as static
|
|
409
|
+
class ProductMapper {
|
|
410
|
+
companion object {
|
|
411
|
+
@JvmStatic
|
|
412
|
+
fun toDomain(dto: ProductDto): Product = Product(dto.id, dto.name)
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
// Java: ProductMapper.toDomain(dto) ✅ (without @JvmStatic: ProductMapper.Companion.toDomain(dto))
|
|
416
|
+
|
|
417
|
+
// @JvmField — exposes Kotlin property as Java field (no getter/setter)
|
|
418
|
+
class Config {
|
|
419
|
+
companion object {
|
|
420
|
+
@JvmField val BASE_URL = "https://api.example.com"
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
// Java: Config.BASE_URL ✅
|
|
424
|
+
|
|
425
|
+
// @JvmOverloads — generates overloaded methods for default parameters
|
|
426
|
+
class ProductService @JvmOverloads constructor(
|
|
427
|
+
val baseUrl: String,
|
|
428
|
+
val timeout: Int = 30,
|
|
429
|
+
val retries: Int = 3,
|
|
430
|
+
)
|
|
431
|
+
// Java: new ProductService("url") ✅ (without: must pass all 3 params)
|
|
432
|
+
|
|
433
|
+
// @Throws — declares checked exceptions for Java callers
|
|
434
|
+
@Throws(IOException::class)
|
|
435
|
+
fun readFile(path: String): String { /* ... */ }
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
### Calling Kotlin Suspend from Java (Bridge Pattern)
|
|
439
|
+
|
|
440
|
+
```java
|
|
441
|
+
// Use CoroutineScope from Java via CoroutinesInstrumentationHelper or wrapper
|
|
442
|
+
// ⚠️ Recommended: write a non-suspend wrapper in Kotlin
|
|
443
|
+
|
|
444
|
+
// Kotlin wrapper (bridge.kt)
|
|
445
|
+
object ProductBridge {
|
|
446
|
+
@JvmStatic
|
|
447
|
+
fun getProducts(scope: CoroutineScope, callback: ProductCallback) {
|
|
448
|
+
scope.launch {
|
|
449
|
+
try {
|
|
450
|
+
val items = getProductsUseCase()
|
|
451
|
+
callback.onSuccess(items)
|
|
452
|
+
} catch (e: Exception) {
|
|
453
|
+
callback.onError(e.message ?: "Error")
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
// Java side
|
|
460
|
+
ProductBridge.getProducts(lifecycleScope, new ProductCallback() {
|
|
461
|
+
@Override public void onSuccess(List<Product> items) { /* update UI */ }
|
|
462
|
+
@Override public void onError(String message) { /* show error */ }
|
|
463
|
+
});
|
|
464
|
+
```
|
|
465
|
+
|
|
466
|
+
### Java Common Pitfalls
|
|
467
|
+
|
|
468
|
+
| Pitfall | Fix |
|
|
469
|
+
|---------|-----|
|
|
470
|
+
| NullPointerException | `@NonNull` / `@Nullable` + null checks |
|
|
471
|
+
| Memory leak (Activity in async) | `WeakReference<Activity>` or cancel on `onDestroy` |
|
|
472
|
+
| Main thread network call | `Executors.newSingleThreadExecutor()` |
|
|
473
|
+
| No `Call.cancel()` | Store reference, cancel in `onDestroy` |
|
|
474
|
+
| Anonymous inner class holding outer ref | Use static inner class |
|
|
475
|
+
|
|
476
|
+
---
|
|
477
|
+
|
|
257
478
|
> Multi-module Gradle + Hilt + Compose + offline-first.
|
|
258
479
|
> Clean Architecture with domain module having zero dependencies.
|
|
480
|
+
> Java legacy: use LiveData + Retrofit callbacks. Bridge Kotlin suspend with wrapper functions.
|
package/bin/install.mjs
CHANGED
|
@@ -70,7 +70,7 @@ const fail = m => log(` ${c.red}✗${c.reset} ${m}`);
|
|
|
70
70
|
|
|
71
71
|
function banner() {
|
|
72
72
|
log(`\n${c.bold}${c.cyan} ┌──────────────────────────────────────────────────┐`);
|
|
73
|
-
log(` │ 📱 @buivietphi/skill-mobile-mt v1.4.
|
|
73
|
+
log(` │ 📱 @buivietphi/skill-mobile-mt v1.4.3 │`);
|
|
74
74
|
log(` │ Master Senior Mobile Engineer │`);
|
|
75
75
|
log(` │ │`);
|
|
76
76
|
log(` │ Claude · Cline · Roo Code · Cursor · Windsurf │`);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@buivietphi/skill-mobile-mt",
|
|
3
|
-
"version": "1.4.
|
|
4
|
-
"description": "Master Senior Mobile Engineer skill for AI agents. Pre-built patterns from
|
|
3
|
+
"version": "1.4.3",
|
|
4
|
+
"description": "Master Senior Mobile Engineer skill for AI agents. Pre-built patterns from 30+ production repos. React Native, Flutter, iOS, Android. Supports Claude, Cline, Cursor, Windsurf, Copilot, Codex, Gemini, Kimi, Kilo Code, Kiro, Antigravity.",
|
|
5
5
|
"author": "buivietphi",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"keywords": [
|