packwise-skills 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.
- package/.cursorrules +23 -0
- package/CLAUDE.md +25 -0
- package/README.md +295 -0
- package/audit.md +224 -0
- package/bin/packwise.js +155 -0
- package/package.json +31 -0
- package/skill.md +719 -0
- package/sub-skills/ai/local-llm.md +183 -0
- package/sub-skills/ai/python-ml.md +164 -0
- package/sub-skills/backend/go-server.md +184 -0
- package/sub-skills/backend/java-spring.md +241 -0
- package/sub-skills/backend/node-server.md +164 -0
- package/sub-skills/backend/php-laravel.md +175 -0
- package/sub-skills/backend/python-server.md +164 -0
- package/sub-skills/backend/rust-backend.md +118 -0
- package/sub-skills/cli/python-cli.md +236 -0
- package/sub-skills/cli/sdk-library.md +497 -0
- package/sub-skills/cloud/ci-cd-pipelines.md +350 -0
- package/sub-skills/cloud/docker.md +191 -0
- package/sub-skills/cloud/kubernetes.md +277 -0
- package/sub-skills/cloud/payment-integration.md +307 -0
- package/sub-skills/cross-platform/multiplatform.md +252 -0
- package/sub-skills/desktop/electron.md +783 -0
- package/sub-skills/desktop/game-dev.md +443 -0
- package/sub-skills/desktop/native-app.md +123 -0
- package/sub-skills/desktop/scenarios.md +443 -0
- package/sub-skills/desktop/smart-platforms.md +324 -0
- package/sub-skills/desktop/tauri.md +428 -0
- package/sub-skills/desktop/vr-ar.md +252 -0
- package/sub-skills/desktop/web-to-desktop.md +153 -0
- package/sub-skills/embedded/car-infotainment.md +129 -0
- package/sub-skills/embedded/esp32.md +184 -0
- package/sub-skills/embedded/ros.md +150 -0
- package/sub-skills/embedded/stm32.md +160 -0
- package/sub-skills/mobile/android.md +322 -0
- package/sub-skills/mobile/capacitor.md +232 -0
- package/sub-skills/mobile/flutter-mobile.md +138 -0
- package/sub-skills/mobile/harmonyos.md +150 -0
- package/sub-skills/mobile/ios.md +245 -0
- package/sub-skills/mobile/react-native.md +443 -0
- package/sub-skills/mobile/wearables.md +230 -0
- package/sub-skills/plugins/browser-extension.md +308 -0
- package/sub-skills/plugins/jetbrains-plugin.md +226 -0
- package/sub-skills/plugins/vscode-extension.md +204 -0
- package/sub-skills/security/security-tools.md +174 -0
- package/sub-skills/web/monorepo.md +274 -0
- package/sub-skills/web/pwa.md +220 -0
- package/sub-skills/web/serverless-edge.md +295 -0
- package/sub-skills/web/spa.md +266 -0
- package/sub-skills/web/ssr.md +228 -0
- package/sub-skills/web/wasm.md +243 -0
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
# STM32 Embedded Build Sub-Skill
|
|
2
|
+
|
|
3
|
+
Build firmware for STM32 microcontrollers using STM32CubeIDE, Keil MDK, or PlatformIO.
|
|
4
|
+
|
|
5
|
+
**Current versions**: STM32CubeIDE 1.17 / STM32CubeMX 6.13 / ARM GCC 13.x (2025-2026)
|
|
6
|
+
|
|
7
|
+
## When to Use
|
|
8
|
+
|
|
9
|
+
- Industrial control systems
|
|
10
|
+
- IoT sensor nodes and gateways
|
|
11
|
+
- Motor control applications
|
|
12
|
+
- Medical devices
|
|
13
|
+
- Automotive ECU (non-safety-critical)
|
|
14
|
+
- Consumer electronics firmware
|
|
15
|
+
|
|
16
|
+
## STM32 Family Overview
|
|
17
|
+
|
|
18
|
+
| Family | Core | Speed | Flash | Best For |
|
|
19
|
+
|--------|------|-------|-------|----------|
|
|
20
|
+
| STM32F0 | Cortex-M0 | 48MHz | 16-256KB | Cost-sensitive, basic control |
|
|
21
|
+
| STM32F1 | Cortex-M3 | 72MHz | 16-1024KB | General purpose (legacy, very popular) |
|
|
22
|
+
| STM32F4 | Cortex-M4F | 168-200MHz | 512KB-2MB | DSP, audio, mid-range processing |
|
|
23
|
+
| STM32G0 | Cortex-M0+ | 64MHz | 16-512KB | Low power, cost-sensitive |
|
|
24
|
+
| STM32G4 | Cortex-M4F | 170MHz | 128-512KB | Analog-rich, motor control |
|
|
25
|
+
| STM32H7 | Cortex-M7+M4 | 480MHz | 1-2MB | High-performance, display, audio |
|
|
26
|
+
| STM32L0 | Cortex-M0+ | 32MHz | 16-192KB | Ultra-low power |
|
|
27
|
+
| STM32L4 | Cortex-M4F | 80MHz | 256KB-1MB | Low power + performance |
|
|
28
|
+
| STM32U5 | Cortex-M33 | 160MHz | 256KB-2MB | Ultra-low power + security |
|
|
29
|
+
| STM32WB | Cortex-M4+M0+ | 64MHz | 256KB-1MB | Bluetooth LE + application |
|
|
30
|
+
| STM32WL | Cortex-M4+M0+ | 48MHz | 64-256KB | LoRa/LoRaWAN + application |
|
|
31
|
+
| STM32MP1/2 | Cortex-A7/M4 | 650-1200MHz | External | Linux + real-time coprocessor |
|
|
32
|
+
|
|
33
|
+
## Prerequisites
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
# STM32CubeIDE (all-in-one: editor + compiler + debugger)
|
|
37
|
+
# Download from st.com/stm32cubeide
|
|
38
|
+
|
|
39
|
+
# OR: ARM GCC toolchain + STM32CubeMX + VS Code
|
|
40
|
+
# ARM GCC:
|
|
41
|
+
sudo apt install gcc-arm-none-eabi # Linux
|
|
42
|
+
brew install --cask gcc-arm-embedded # macOS
|
|
43
|
+
|
|
44
|
+
# STM32CubeMX (pin/peripheral configuration)
|
|
45
|
+
# Download from st.com/stm32cubemx
|
|
46
|
+
|
|
47
|
+
# OR: PlatformIO (cross-platform build system)
|
|
48
|
+
pip install platformio
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## STM32CubeIDE Build
|
|
52
|
+
|
|
53
|
+
### Project Setup
|
|
54
|
+
|
|
55
|
+
```
|
|
56
|
+
STM32CubeIDE:
|
|
57
|
+
1. File → New → STM32 Project
|
|
58
|
+
2. Select MCU/Board (e.g., STM32F407VG)
|
|
59
|
+
3. Configure pins in .ioc file (CubeMX integrated)
|
|
60
|
+
4. Generate code
|
|
61
|
+
5. Write application code in Core/Src/main.c
|
|
62
|
+
6. Build: Project → Build All (Ctrl+B)
|
|
63
|
+
7. Debug: Run → Debug (ST-Link/J-Link)
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Build Output
|
|
67
|
+
|
|
68
|
+
```
|
|
69
|
+
Debug/ or Release/
|
|
70
|
+
├── myproject.elf ← Debug binary (with symbols)
|
|
71
|
+
├── myproject.hex ← Intel HEX (for programmer)
|
|
72
|
+
├── myproject.bin ← Raw binary (for bootloader/OTA)
|
|
73
|
+
└── myproject.map ← Memory map (linker output)
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Command Line Build
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
# Build with ARM GCC
|
|
80
|
+
arm-none-eabi-gcc -mcpu=cortex-m4 -mthumb -mfloat-abi=hard -mfpu=fpv4-sp-d16 \
|
|
81
|
+
-O2 -g -Wall \
|
|
82
|
+
-DSTM32F407xx \
|
|
83
|
+
-IInc -IDrivers/STM32F4xx_HAL_Driver/Inc \
|
|
84
|
+
-ICore/Inc \
|
|
85
|
+
Src/main.c Src/stm32f4xx_it.c \
|
|
86
|
+
-TSTM32F407VGTX_FLASH.ld \
|
|
87
|
+
-o build/myproject.elf \
|
|
88
|
+
-lc -lm -lnosys
|
|
89
|
+
|
|
90
|
+
# Generate .bin from .elf
|
|
91
|
+
arm-none-eabi-objcopy -O binary build/myproject.elf build/myproject.bin
|
|
92
|
+
|
|
93
|
+
# Generate .hex from .elf
|
|
94
|
+
arm-none-eabi-objcopy -O ihex build/myproject.elf build/myproject.hex
|
|
95
|
+
|
|
96
|
+
# Flash with ST-Link
|
|
97
|
+
st-flash write build/myproject.bin 0x08000000
|
|
98
|
+
|
|
99
|
+
# Flash with J-Link
|
|
100
|
+
JLinkExe -device STM32F407VG -if SWD -speed 4000 -CommandFile flash.jlink
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Flash Size Report
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
arm-none-eabi-size build/myproject.elf
|
|
107
|
+
# Output:
|
|
108
|
+
# text data bss dec hex filename
|
|
109
|
+
# 32768 1024 4096 37888 9400 build/myproject.elf
|
|
110
|
+
# text = code + const data (Flash)
|
|
111
|
+
# data = initialized variables (Flash + RAM)
|
|
112
|
+
# bss = zero-initialized variables (RAM only)
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## PlatformIO Build
|
|
116
|
+
|
|
117
|
+
```ini
|
|
118
|
+
; platformio.ini
|
|
119
|
+
[env:stm32f407vg]
|
|
120
|
+
platform = ststm32
|
|
121
|
+
board = disco_f407vg
|
|
122
|
+
framework = stm32cube ; or: arduino, cmsis, zephyr
|
|
123
|
+
build_flags = -O2 -DSTM32F407xx
|
|
124
|
+
upload_protocol = stlink
|
|
125
|
+
debug_tool = stlink
|
|
126
|
+
monitor_speed = 115200
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
pio run # Build
|
|
131
|
+
pio run -t upload # Flash
|
|
132
|
+
pio run -t debug # Debug (GDB + OpenOCD/ST-Link)
|
|
133
|
+
pio device monitor # Serial monitor
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## RTOS Options for STM32
|
|
137
|
+
|
|
138
|
+
| RTOS | License | RAM (min) | Best For |
|
|
139
|
+
|------|---------|-----------|----------|
|
|
140
|
+
| FreeRTOS | MIT | ~5KB | Most popular, AWS-supported |
|
|
141
|
+
| Zephyr | Apache 2.0 | ~30KB | Full-featured, Linux-like ecosystem |
|
|
142
|
+
| RT-Thread | Apache 2.0 | ~3KB | Chinese ecosystem, IoT-focused |
|
|
143
|
+
| Azure RTOS (ThreadX) | MIT | ~2KB | Microsoft, very small footprint |
|
|
144
|
+
| CMSIS-RTOS2 | Apache 2.0 | N/A | ARM standard API (wraps FreeRTOS/ThreadX) |
|
|
145
|
+
| bare-metal | N/A | 0 | Simple applications, no OS |
|
|
146
|
+
|
|
147
|
+
## Common Pitfalls
|
|
148
|
+
|
|
149
|
+
| Issue | Fix |
|
|
150
|
+
|-------|-----|
|
|
151
|
+
| Flash size overflow | Use `-Os` (optimize for size); enable LTO; remove unused HAL modules |
|
|
152
|
+
| RAM overflow | Reduce stack/heap size in linker script; use `.data` and `.bss` sections properly |
|
|
153
|
+
| HardFault crash | Check stack overflow (increase stack size); verify interrupt priorities |
|
|
154
|
+
| Clock misconfiguration | Use CubeMX to configure RCC; verify HSE/HSI oscillator source |
|
|
155
|
+
| Debug connection fails | Check ST-Link firmware; verify SWD pins not reconfigured as GPIO |
|
|
156
|
+
| Peripheral not working | Enable peripheral clock in RCC; check pin AF mapping in CubeMX |
|
|
157
|
+
| Power consumption too high | Use low-power modes (STOP/STANDBY); disable unused peripherals |
|
|
158
|
+
| Bootloader jump fails | Set MSP and PC correctly; disable interrupts before jump |
|
|
159
|
+
| OTA update fails | Verify flash write alignment (usually 256-byte or 1KB pages) |
|
|
160
|
+
| Floating point not working | Use `-mfloat-abi=hard -mfpu=fpv4-sp-d16`; enable FPU in CPACR register |
|
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
# Android Native Build Sub-Skill
|
|
2
|
+
|
|
3
|
+
Build and publish Kotlin/Java native Android applications.
|
|
4
|
+
|
|
5
|
+
**Current version**: Android 15 (API 35) / AGP 8.7.x / Gradle 8.10+ / JDK 17 (2025-2026)
|
|
6
|
+
|
|
7
|
+
## When to Use
|
|
8
|
+
|
|
9
|
+
- Native Android applications (Kotlin recommended, Java supported)
|
|
10
|
+
- Apps requiring deep Android platform integration
|
|
11
|
+
- Apps published to Google Play, Huawei AppGallery, or Xiaomi GetApps
|
|
12
|
+
|
|
13
|
+
## Prerequisites
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
# JDK 17 (REQUIRED for AGP 8.x)
|
|
17
|
+
# Android Studio (includes JDK 17 bundled as JBR)
|
|
18
|
+
# OR: standalone JDK 17
|
|
19
|
+
|
|
20
|
+
# Android SDK 35 (via Android Studio SDK Manager)
|
|
21
|
+
# NDK (if using native code)
|
|
22
|
+
|
|
23
|
+
# Verify
|
|
24
|
+
java -version # Should show 17.x
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Build
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
./gradlew assembleDebug # Debug APK
|
|
31
|
+
./gradlew assembleRelease # Release APK
|
|
32
|
+
./gradlew bundleRelease # AAB (required by Google Play)
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Required Build Configuration (AGP 8.x)
|
|
36
|
+
|
|
37
|
+
```kotlin
|
|
38
|
+
// build.gradle.kts (app-level)
|
|
39
|
+
android {
|
|
40
|
+
namespace = "com.example.myapp" // REQUIRED since AGP 8.0 (replaces package in AndroidManifest)
|
|
41
|
+
compileSdk = 35 // Should match latest API level
|
|
42
|
+
|
|
43
|
+
defaultConfig {
|
|
44
|
+
applicationId = "com.example.myapp"
|
|
45
|
+
minSdk = 24 // Android 7.0
|
|
46
|
+
targetSdk = 35 // REQUIRED: Google Play mandates API 35 as of 2025
|
|
47
|
+
versionCode = 1
|
|
48
|
+
versionName = "1.0.0"
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
```xml
|
|
54
|
+
<!-- AndroidManifest.xml — REMOVE package attribute (AGP 8.x) -->
|
|
55
|
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
|
56
|
+
<!-- NO package="..." attribute here -->
|
|
57
|
+
</manifest>
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### gradle.properties (Modern Defaults)
|
|
61
|
+
|
|
62
|
+
```properties
|
|
63
|
+
# gradle.properties
|
|
64
|
+
android.useAndroidX=true
|
|
65
|
+
android.nonTransitiveRClass=true
|
|
66
|
+
org.gradle.jvmargs=-Xmx4g -XX:+UseG1GC
|
|
67
|
+
org.gradle.parallel=true
|
|
68
|
+
org.gradle.caching=true
|
|
69
|
+
org.gradle.configuration-cache=true
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Signing (Secure Approach)
|
|
73
|
+
|
|
74
|
+
### Generate Upload Key
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
keytool -genkey -v -keystore upload-key.jks \
|
|
78
|
+
-keyalg RSA -keysize 2048 -validity 10000 \
|
|
79
|
+
-alias upload
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Secure Signing Configuration
|
|
83
|
+
|
|
84
|
+
```kotlin
|
|
85
|
+
// build.gradle.kts — NEVER hardcode passwords
|
|
86
|
+
signingConfigs {
|
|
87
|
+
create("release") {
|
|
88
|
+
storeFile = file(System.getenv("KEYSTORE_PATH") ?: "../keystore/upload-key.jks")
|
|
89
|
+
storePassword = System.getenv("KEYSTORE_PASSWORD") ?: ""
|
|
90
|
+
keyAlias = System.getenv("KEY_ALIAS") ?: ""
|
|
91
|
+
keyPassword = System.getenv("KEY_PASSWORD") ?: ""
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
buildTypes {
|
|
96
|
+
release {
|
|
97
|
+
signingConfig = signingConfigs.getByName("release")
|
|
98
|
+
isMinifyEnabled = true
|
|
99
|
+
isShrinkResources = true
|
|
100
|
+
proguardFiles(
|
|
101
|
+
getDefaultProguardFile("proguard-android-optimize.txt"),
|
|
102
|
+
"proguard-rules.pro"
|
|
103
|
+
)
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### Play App Signing (Recommended)
|
|
109
|
+
|
|
110
|
+
Google Play App Signing separates the **upload key** (you hold) from the **signing key** (Google holds):
|
|
111
|
+
|
|
112
|
+
- **Upload key**: Signs your AAB before uploading. If lost, can be reset in Play Console.
|
|
113
|
+
- **Signing key**: Signs the final APK delivered to users. Google manages this securely.
|
|
114
|
+
- Enroll in Google Play Console → Release → Setup → App signing
|
|
115
|
+
|
|
116
|
+
## 16KB Page Alignment (Android 15 Requirement)
|
|
117
|
+
|
|
118
|
+
Android 15 devices may use 16KB memory pages. All native libraries (.so files) must be 16KB aligned.
|
|
119
|
+
|
|
120
|
+
```kotlin
|
|
121
|
+
// build.gradle.kts
|
|
122
|
+
android {
|
|
123
|
+
packaging {
|
|
124
|
+
jniLibs {
|
|
125
|
+
pageAlignSharedLibs = true // AGP 8.5+
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
# Check alignment
|
|
133
|
+
unzip -l app.apk | grep "\.so$"
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
**Apps without native code are NOT affected.**
|
|
137
|
+
|
|
138
|
+
## Network Security Config
|
|
139
|
+
|
|
140
|
+
```xml
|
|
141
|
+
<!-- res/xml/network_security_config.xml -->
|
|
142
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
143
|
+
<network-security-config>
|
|
144
|
+
<base-config cleartextTrafficPermitted="false">
|
|
145
|
+
<trust-anchors>
|
|
146
|
+
<certificates src="system" />
|
|
147
|
+
</trust-anchors>
|
|
148
|
+
</base-config>
|
|
149
|
+
</network-security-config>
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
```xml
|
|
153
|
+
<!-- AndroidManifest.xml -->
|
|
154
|
+
<application
|
|
155
|
+
android:networkSecurityConfig="@xml/network_security_config"
|
|
156
|
+
... >
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## Android Keystore (Runtime Key Storage)
|
|
160
|
+
|
|
161
|
+
For storing sensitive data at runtime (tokens, credentials), use Android Keystore — NOT JKS files:
|
|
162
|
+
|
|
163
|
+
```kotlin
|
|
164
|
+
// EncryptedSharedPreferences (recommended for key-value storage)
|
|
165
|
+
val masterKey = MasterKey.Builder(context)
|
|
166
|
+
.setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
|
|
167
|
+
.build()
|
|
168
|
+
|
|
169
|
+
val securePrefs = EncryptedSharedPreferences.create(
|
|
170
|
+
context, "secret_prefs", masterKey,
|
|
171
|
+
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
|
|
172
|
+
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
|
|
173
|
+
)
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
## Foreground Service Types (Android 14+)
|
|
177
|
+
|
|
178
|
+
Starting with Android 14 (API 34), every foreground service MUST declare a type:
|
|
179
|
+
|
|
180
|
+
```xml
|
|
181
|
+
<service
|
|
182
|
+
android:name=".MyService"
|
|
183
|
+
android:foregroundServiceType="dataSync" />
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
Valid types: `camera`, `connectedDevice`, `dataSync`, `health`, `location`, `mediaPlayback`, `microphone`, `phoneCall`, `shortService`, `specialUse`.
|
|
187
|
+
|
|
188
|
+
## Permissions Policy
|
|
189
|
+
|
|
190
|
+
```xml
|
|
191
|
+
<!-- Android 13+ notification permission -->
|
|
192
|
+
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
|
193
|
+
|
|
194
|
+
<!-- Android 13+ granular media permissions (replaces READ_EXTERNAL_STORAGE) -->
|
|
195
|
+
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
|
|
196
|
+
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
|
|
197
|
+
|
|
198
|
+
<!-- Use system photo picker instead of READ_MEDIA_IMAGES when possible -->
|
|
199
|
+
<!-- No permission needed: ActivityResultContracts.PickVisualMedia() -->
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
## Store Publishing Checklist
|
|
203
|
+
|
|
204
|
+
| Step | Description |
|
|
205
|
+
|------|-------------|
|
|
206
|
+
| 1. Register developer | Google Play ($25 one-time), Huawei (free), Xiaomi (free) |
|
|
207
|
+
| 2. Generate signed AAB | `./gradlew bundleRelease` |
|
|
208
|
+
| 3. Privacy policy | Required URL — must be accessible without login |
|
|
209
|
+
| 4. Data Safety section | Declare all data collection in Play Console (Mandatory) |
|
|
210
|
+
| 5. Data deletion | Apps with account creation MUST provide data deletion option |
|
|
211
|
+
| 6. App icon | 512x512 PNG |
|
|
212
|
+
| 7. Screenshots | Phone + tablet |
|
|
213
|
+
| 8. Description | App name, short description, full description |
|
|
214
|
+
| 9. Content rating | IARC rating questionnaire |
|
|
215
|
+
| 10. Target SDK | Must be API 35 (as of 2025/2026) |
|
|
216
|
+
| 11. Submit review | Google Play typically 1–3 days |
|
|
217
|
+
|
|
218
|
+
## Build Optimization
|
|
219
|
+
|
|
220
|
+
### ABI Splits (Reduce APK Size)
|
|
221
|
+
|
|
222
|
+
```kotlin
|
|
223
|
+
// build.gradle.kts
|
|
224
|
+
android {
|
|
225
|
+
splits {
|
|
226
|
+
abi {
|
|
227
|
+
isEnable = true
|
|
228
|
+
reset()
|
|
229
|
+
include("arm64-v8a", "armeabi-v7a", "x86_64")
|
|
230
|
+
isUniversalApk = false
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
### R8 Code Shrinking
|
|
237
|
+
|
|
238
|
+
```kotlin
|
|
239
|
+
// build.gradle.kts
|
|
240
|
+
android {
|
|
241
|
+
buildTypes {
|
|
242
|
+
release {
|
|
243
|
+
isMinifyEnabled = true
|
|
244
|
+
isShrinkResources = true
|
|
245
|
+
proguardFiles(
|
|
246
|
+
getDefaultProguardFile("proguard-android-optimize.txt"),
|
|
247
|
+
"proguard-rules.pro"
|
|
248
|
+
)
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
### Build Variant Management
|
|
255
|
+
|
|
256
|
+
```kotlin
|
|
257
|
+
// build.gradle.kts
|
|
258
|
+
android {
|
|
259
|
+
flavorDimensions += "env"
|
|
260
|
+
productFlavors {
|
|
261
|
+
create("dev") {
|
|
262
|
+
dimension = "env"
|
|
263
|
+
applicationIdSuffix = ".dev"
|
|
264
|
+
versionNameSuffix = "-dev"
|
|
265
|
+
}
|
|
266
|
+
create("staging") {
|
|
267
|
+
dimension = "env"
|
|
268
|
+
applicationIdSuffix = ".staging"
|
|
269
|
+
}
|
|
270
|
+
create("prod") {
|
|
271
|
+
dimension = "env"
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
## CI/CD — GitHub Actions
|
|
278
|
+
|
|
279
|
+
```yaml
|
|
280
|
+
name: Android Build
|
|
281
|
+
on:
|
|
282
|
+
push:
|
|
283
|
+
tags: ['v*']
|
|
284
|
+
jobs:
|
|
285
|
+
build:
|
|
286
|
+
runs-on: ubuntu-latest
|
|
287
|
+
steps:
|
|
288
|
+
- uses: actions/checkout@v4
|
|
289
|
+
- uses: actions/setup-java@v4
|
|
290
|
+
with:
|
|
291
|
+
distribution: 'temurin'
|
|
292
|
+
java-version: '17'
|
|
293
|
+
- name: Decode Keystore
|
|
294
|
+
run: echo "${{ secrets.RELEASE_KEYSTORE_BASE64 }}" | base64 --decode > app/release.jks
|
|
295
|
+
- name: Build AAB
|
|
296
|
+
env:
|
|
297
|
+
KEYSTORE_PATH: release.jks
|
|
298
|
+
KEYSTORE_PASSWORD: ${{ secrets.KEYSTORE_PASSWORD }}
|
|
299
|
+
KEY_ALIAS: ${{ secrets.KEY_ALIAS }}
|
|
300
|
+
KEY_PASSWORD: ${{ secrets.KEY_PASSWORD }}
|
|
301
|
+
run: ./gradlew bundleRelease
|
|
302
|
+
- uses: actions/upload-artifact@v4
|
|
303
|
+
with:
|
|
304
|
+
name: aab
|
|
305
|
+
path: app/build/outputs/bundle/release/*.aab
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
## Common Pitfalls
|
|
309
|
+
|
|
310
|
+
| Issue | Fix |
|
|
311
|
+
|-------|-----|
|
|
312
|
+
| "Namespace not specified" | Add `namespace = "com.example.app"` in build.gradle (AGP 8.x requires it) |
|
|
313
|
+
| Signing error | Check environment variables; never hardcode passwords |
|
|
314
|
+
| ProGuard crash | Add `-keep` rules for models, native modules, serialization |
|
|
315
|
+
| Target SDK rejected | Google Play requires `targetSdk = 35` as of 2025 |
|
|
316
|
+
| 16KB alignment error | Add `pageAlignSharedLibs = true` in build.gradle |
|
|
317
|
+
| Foreground service crash | Declare `foregroundServiceType` in AndroidManifest (API 34+) |
|
|
318
|
+
| Data Safety rejection | Complete Data Safety section in Play Console |
|
|
319
|
+
| Privacy policy rejected | URL must be live, accessible without login, match Data Safety declaration |
|
|
320
|
+
| Cleartext traffic blocked | Android 9+ blocks HTTP by default; use HTTPS or configure network_security_config |
|
|
321
|
+
| `READ_EXTERNAL_STORAGE` not working | Android 13+ uses `READ_MEDIA_IMAGES`/`READ_MEDIA_VIDEO` instead |
|
|
322
|
+
| Play App Signing key lost | Upload key can be reset in Play Console; signing key is managed by Google |
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
# Capacitor Mobile Build Sub-Skill
|
|
2
|
+
|
|
3
|
+
Package web applications as native mobile apps using Capacitor.
|
|
4
|
+
|
|
5
|
+
**Current version**: Capacitor 8.x / Capacitor CLI 8.x (2025-2026)
|
|
6
|
+
|
|
7
|
+
> ⚠️ **Breaking changes since Capacitor 6**:
|
|
8
|
+
> - **Node.js 22+ required** (was 18+). **JDK 21 required** (was 17). **iOS deployment target 15.0** (was 13.0). **Android minSdk 24** (was 22). **Android compileSdk/targetSdk 36** (was 34).
|
|
9
|
+
> - `android.adjustMarginsForEdgeToEdge` config removed (v8) — use System Bars plugin with CSS `env()` variables.
|
|
10
|
+
> - `bridge_layout_main.xml` renamed to `capacitor_bridge_layout_main.xml` (v8).
|
|
11
|
+
> - Gradle property syntax requires `=` (e.g., `namespace = "com.example"`).
|
|
12
|
+
> - iOS now defaults to SPM (Swift Package Manager) for new projects (v8).
|
|
13
|
+
> - Plugin type aliases removed in v7 (e.g., `AppRestoredResult` → `RestoredListenerEvent`).
|
|
14
|
+
> - Run `npx cap migrate` for automated migration.
|
|
15
|
+
> - See [capacitorjs.com/docs/updating/8-0](https://capacitorjs.com/docs/updating/8-0).
|
|
16
|
+
|
|
17
|
+
## When to Use
|
|
18
|
+
|
|
19
|
+
- Have an existing web app (React, Vue, Svelte, Angular, vanilla JS)
|
|
20
|
+
- Need native device access (camera, GPS, filesystem, push notifications)
|
|
21
|
+
- Want a single codebase for web + iOS + Android
|
|
22
|
+
- Don't need deep native UI customization
|
|
23
|
+
|
|
24
|
+
## Key Features
|
|
25
|
+
|
|
26
|
+
- **WebView-based** — web app runs inside a native WebView container
|
|
27
|
+
- **Native plugin ecosystem** — camera, geolocation, filesystem, push, biometrics, etc.
|
|
28
|
+
- **Live Updates** — push web content updates without app store review (via `@capacitor/live-updates`)
|
|
29
|
+
- **Progressive adoption** — add Capacitor to existing web projects incrementally
|
|
30
|
+
- **Platform APIs** — access native features via TypeScript-friendly plugin APIs
|
|
31
|
+
|
|
32
|
+
## Prerequisites
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
# Node.js 22+ (REQUIRED for Capacitor 8)
|
|
36
|
+
# For Android: Android Studio (2025.2.1+) + JDK 21
|
|
37
|
+
# For iOS: Xcode 26+ (macOS only), iOS deployment target 15.0+
|
|
38
|
+
# CocoaPods or SPM (SPM is default for new Capacitor 8 iOS projects)
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Project Setup
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
# Install Capacitor
|
|
45
|
+
npm install @capacitor/core @capacitor/cli
|
|
46
|
+
|
|
47
|
+
# Initialize (interactive — sets appName, appId, webDir)
|
|
48
|
+
npx cap init
|
|
49
|
+
|
|
50
|
+
# Add platforms
|
|
51
|
+
npx cap add android
|
|
52
|
+
npx cap add ios
|
|
53
|
+
|
|
54
|
+
# Install common plugins
|
|
55
|
+
npm install @capacitor/camera @capacitor/geolocation @capacitor/push-notifications
|
|
56
|
+
npm install @capacitor/filesystem @capacitor/haptics @capacitor/share
|
|
57
|
+
npm install @capacitor/local-notifications @capacitor/biometric
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Configuration
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
// capacitor.config.ts
|
|
64
|
+
import type { CapacitorConfig } from '@capacitor/cli';
|
|
65
|
+
|
|
66
|
+
const config: CapacitorConfig = {
|
|
67
|
+
appId: 'com.example.myapp',
|
|
68
|
+
appName: 'MyApp',
|
|
69
|
+
webDir: 'dist', // must match your framework's build output directory
|
|
70
|
+
server: {
|
|
71
|
+
androidScheme: 'https', // required for modern WebView features
|
|
72
|
+
// url: 'http://192.168.1.100:5173', // dev mode: live reload from dev server
|
|
73
|
+
// cleartext: true, // dev mode: allow HTTP
|
|
74
|
+
},
|
|
75
|
+
android: {
|
|
76
|
+
buildOptions: {
|
|
77
|
+
keystorePath: undefined, // set for release signing
|
|
78
|
+
keystoreAlias: undefined,
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
ios: {
|
|
82
|
+
scheme: 'MyApp', // Xcode scheme name
|
|
83
|
+
contentInset: 'automatic',
|
|
84
|
+
},
|
|
85
|
+
plugins: {
|
|
86
|
+
PushNotifications: {
|
|
87
|
+
presentationOptions: ['badge', 'sound', 'alert'],
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
export default config;
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Build Workflow
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
# 1. Build your web app first
|
|
99
|
+
npm run build # outputs to dist/
|
|
100
|
+
|
|
101
|
+
# 2. Copy web assets to native projects
|
|
102
|
+
npx cap copy android
|
|
103
|
+
npx cap copy ios
|
|
104
|
+
|
|
105
|
+
# 3. Sync (copy + update native dependencies)
|
|
106
|
+
npx cap sync android
|
|
107
|
+
npx cap sync ios
|
|
108
|
+
|
|
109
|
+
# 4. Open in native IDE for final build
|
|
110
|
+
npx cap open android # Android Studio
|
|
111
|
+
npx cap open ios # Xcode
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## Android Release Build
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
# Generate signing keystore (first time)
|
|
118
|
+
keytool -genkey -v -keystore android/app/my-release-key.jks \
|
|
119
|
+
-keyalg RSA -keysize 2048 -validity 10000 -alias my-key
|
|
120
|
+
|
|
121
|
+
# build.gradle.kts signing config
|
|
122
|
+
signingConfigs {
|
|
123
|
+
create("release") {
|
|
124
|
+
storeFile = file("my-release-key.jks")
|
|
125
|
+
storePassword = System.getenv("KEYSTORE_PASSWORD")
|
|
126
|
+
keyAlias = "my-key"
|
|
127
|
+
keyPassword = System.getenv("KEY_PASSWORD")
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
# Build AAB (Play Store)
|
|
132
|
+
cd android && ./gradlew bundleRelease
|
|
133
|
+
# Output: android/app/build/outputs/bundle/release/app-release.aab
|
|
134
|
+
|
|
135
|
+
# Build APK (direct distribution)
|
|
136
|
+
cd android && ./gradlew assembleRelease
|
|
137
|
+
# Output: android/app/build/outputs/apk/release/app-release-unsigned.apk
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## iOS Release Build
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
# Open Xcode project
|
|
144
|
+
npx cap open ios
|
|
145
|
+
|
|
146
|
+
# In Xcode:
|
|
147
|
+
# 1. Select "Any iOS Device" as target
|
|
148
|
+
# 2. Product → Archive
|
|
149
|
+
# 3. Distribute App → App Store Connect / Ad Hoc / Enterprise
|
|
150
|
+
|
|
151
|
+
# Command line (requires fastlane)
|
|
152
|
+
sudo gem install fastlane
|
|
153
|
+
cd ios/App && fastlane beta # TestFlight
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## Common Pitfalls
|
|
157
|
+
|
|
158
|
+
| Issue | Fix |
|
|
159
|
+
|-------|-----|
|
|
160
|
+
| White screen after build | Check `webDir` in capacitor.config.ts matches framework output dir (dist/build/www) |
|
|
161
|
+
| Resources not synced | Always run `npx cap copy` or `npx cap sync` AFTER `npm run build` |
|
|
162
|
+
| Plugin not working | Run `npx cap sync` after installing new plugins; check plugin supports your platform |
|
|
163
|
+
| Android build fails | Check JDK version (**21 required for v8**); invalidate caches in Android Studio |
|
|
164
|
+
| iOS build fails | Run `cd ios/App && pod install` after adding plugins; iOS target must be **15.0+** |
|
|
165
|
+
| CORS errors in dev | Set `server.url` to dev server and `server.cleartext: true` in config |
|
|
166
|
+
| Keyboard overlaps input | Install `@capacitor/keyboard` and configure `resize` mode |
|
|
167
|
+
| Status bar issues | Use `@capacitor/status-bar` to configure appearance |
|
|
168
|
+
| Push notifications not received | Verify Google Services (Android) / APNs (iOS) certificates configured correctly |
|
|
169
|
+
| `capacitor.config.ts` not found | Ensure file is in project root; Capacitor 6 requires `.ts` or `.json` |
|
|
170
|
+
| Native module crashes on startup | Check Android `minSdkVersion` (**24+ for v8**) / iOS deployment target (**15.0+ for v8**) |
|
|
171
|
+
| App rejected by Play Store | Ensure `androidScheme: 'https'`; Play Store requires HTTPS in WebView |
|
|
172
|
+
| `bridge_layout_main.xml` not found (v8) | Renamed to `capacitor_bridge_layout_main.xml` |
|
|
173
|
+
| Gradle syntax warning | Use `=` syntax: `namespace = "com.example"` not `namespace "com.example"` |
|
|
174
|
+
| Plugin type not found (v7+) | Type aliases removed: `AppRestoredResult` → `RestoredListenerEvent`, etc. |
|
|
175
|
+
|
|
176
|
+
## Plugin Management
|
|
177
|
+
|
|
178
|
+
```bash
|
|
179
|
+
# List installed plugins
|
|
180
|
+
npx cap ls
|
|
181
|
+
|
|
182
|
+
# Update plugins to latest
|
|
183
|
+
npx cap update android
|
|
184
|
+
npx cap update ios
|
|
185
|
+
|
|
186
|
+
# Remove a plugin
|
|
187
|
+
npm uninstall @capacitor/camera
|
|
188
|
+
npx cap sync
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
## CI/CD — GitHub Actions (Android)
|
|
192
|
+
|
|
193
|
+
```yaml
|
|
194
|
+
# .github/workflows/capacitor-android.yml
|
|
195
|
+
name: Capacitor Android
|
|
196
|
+
on:
|
|
197
|
+
push:
|
|
198
|
+
branches: [main]
|
|
199
|
+
|
|
200
|
+
jobs:
|
|
201
|
+
build:
|
|
202
|
+
runs-on: ubuntu-latest
|
|
203
|
+
steps:
|
|
204
|
+
- uses: actions/checkout@v4
|
|
205
|
+
- uses: actions/setup-node@v4
|
|
206
|
+
with:
|
|
207
|
+
node-version: '22'
|
|
208
|
+
- run: npm ci
|
|
209
|
+
- run: npm run build
|
|
210
|
+
- run: npx cap sync android
|
|
211
|
+
- uses: actions/setup-java@v4
|
|
212
|
+
with:
|
|
213
|
+
distribution: 'temurin'
|
|
214
|
+
java-version: '17'
|
|
215
|
+
- run: cd android && chmod +x gradlew && ./gradlew assembleRelease
|
|
216
|
+
- uses: actions/upload-artifact@v4
|
|
217
|
+
with:
|
|
218
|
+
name: apk
|
|
219
|
+
path: android/app/build/outputs/apk/release/*.apk
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
## Capacitor vs Cordova vs PWA
|
|
223
|
+
|
|
224
|
+
| Feature | Capacitor 6 | Cordova | PWA |
|
|
225
|
+
|---------|------------|---------|-----|
|
|
226
|
+
| Architecture | Modern WebView + native bridge | Legacy WebView bridge | Browser APIs only |
|
|
227
|
+
| Plugin API | TypeScript-first, Promise-based | Callback-based | Service Worker + Web APIs |
|
|
228
|
+
| Native UI | Yes (custom native views) | Limited | No |
|
|
229
|
+
| Live Updates | Yes (@capacitor/live-updates) | No (without plugin) | Yes (Service Worker) |
|
|
230
|
+
| Web target | Direct (same codebase) | Requires wrapper | Native |
|
|
231
|
+
| Maintenance | Active (Ionic team) | Community | Browser vendors |
|
|
232
|
+
| Learning curve | Low | Low | Lowest |
|