android-sdd 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/dist/index.js +143 -0
- package/package.json +27 -0
- package/skills/Android Ecosystem/Baseline Profile Generator/SKILL.md +277 -0
- package/skills/Android Ecosystem/Glance/SKILL.md +315 -0
- package/skills/Android Platform/Configuration/SKILL.md +201 -0
- package/skills/Android Platform/Filesystem/SKILL.md +216 -0
- package/skills/Android Platform/Lifecycle/SKILL.md +233 -0
- package/skills/Android Platform/Manifest/SKILL.md +226 -0
- package/skills/Android Platform/Process Death Recovery/SKILL.md +214 -0
- package/skills/Android Platform/Resources/SKILL.md +234 -0
- package/skills/Android Platform/SavedStateHandle/SKILL.md +217 -0
- package/skills/Android Platform/State Restoration/SKILL.md +210 -0
- package/skills/Architecture/Bounded Context/SKILL.md +207 -0
- package/skills/Architecture/Clean Architecture/SKILL.md +229 -0
- package/skills/Architecture/Domain Modeling/SKILL.md +236 -0
- package/skills/Architecture/Entity Design/SKILL.md +243 -0
- package/skills/Architecture/Feature Isolation/SKILL.md +216 -0
- package/skills/Architecture/MVI/SKILL.md +224 -0
- package/skills/Architecture/MVVM/SKILL.md +198 -0
- package/skills/Architecture/Modularization/SKILL.md +194 -0
- package/skills/Architecture/Offline First/SKILL.md +249 -0
- package/skills/Architecture/Repository Pattern/SKILL.md +216 -0
- package/skills/Architecture/Side Effect Management/SKILL.md +278 -0
- package/skills/Architecture/State Management/SKILL.md +229 -0
- package/skills/Architecture/Unidirectional Data Flow/SKILL.md +196 -0
- package/skills/Architecture/Use Case Design/SKILL.md +244 -0
- package/skills/Architecture/Value Object/SKILL.md +226 -0
- package/skills/Build Infrastructure/Build Orchestration/SKILL.md +257 -0
- package/skills/Build Infrastructure/Dependency Compatibility Resolver/SKILL.md +259 -0
- package/skills/Build Infrastructure/Environment Validator/SKILL.md +311 -0
- package/skills/Build System/Build Cache/SKILL.md +233 -0
- package/skills/Build System/Build Flavor Strategy/SKILL.md +171 -0
- package/skills/Build System/Build Variant/SKILL.md +215 -0
- package/skills/Build System/Convention Plugin/SKILL.md +288 -0
- package/skills/Build System/Dependency Management/SKILL.md +261 -0
- package/skills/Build System/Gradle/SKILL.md +284 -0
- package/skills/Build System/Incremental Build/SKILL.md +199 -0
- package/skills/Build System/KAPT/SKILL.md +198 -0
- package/skills/Build System/KSP/SKILL.md +263 -0
- package/skills/Build System/Module Dependency Graph Validation/SKILL.md +223 -0
- package/skills/Build System/Specialized/C++/SKILL.md +308 -0
- package/skills/Build System/Specialized/JNI/SKILL.md +306 -0
- package/skills/Build System/Specialized/NDK/SKILL.md +264 -0
- package/skills/Build System/Version Catalog/SKILL.md +304 -0
- package/skills/Concurrency/Background Processing/SKILL.md +185 -0
- package/skills/Concurrency/Channel/SKILL.md +207 -0
- package/skills/Concurrency/Coroutine/SKILL.md +200 -0
- package/skills/Concurrency/Flow/SKILL.md +179 -0
- package/skills/Concurrency/Mutex Strategy/SKILL.md +185 -0
- package/skills/Concurrency/SharedFlow/SKILL.md +171 -0
- package/skills/Concurrency/StateFlow/SKILL.md +175 -0
- package/skills/Concurrency/Structured Concurrency/SKILL.md +197 -0
- package/skills/Concurrency/Synchronization Policy/SKILL.md +192 -0
- package/skills/Core Language/Annotation Processing/SKILL.md +224 -0
- package/skills/Core Language/DSL/SKILL.md +186 -0
- package/skills/Core Language/Extension Functions Design/SKILL.md +191 -0
- package/skills/Core Language/Immutability/SKILL.md +156 -0
- package/skills/Core Language/KMP/SKILL.md +182 -0
- package/skills/Core Language/Kotlin/SKILL.md +187 -0
- package/skills/Core Language/Reactive State Management/SKILL.md +228 -0
- package/skills/Core Language/Reactive Streams/SKILL.md +235 -0
- package/skills/Core Language/Serialization/SKILL.md +191 -0
- package/skills/Data Layer/Cache Strategy/SKILL.md +261 -0
- package/skills/Data Layer/Conflict Resolution/SKILL.md +248 -0
- package/skills/Data Layer/DAO/SKILL.md +225 -0
- package/skills/Data Layer/DTO Mapping/SKILL.md +269 -0
- package/skills/Data Layer/DataStore/SKILL.md +264 -0
- package/skills/Data Layer/Database Versioning Strategy/SKILL.md +215 -0
- package/skills/Data Layer/Encrypted Database/SKILL.md +212 -0
- package/skills/Data Layer/File Storage/SKILL.md +247 -0
- package/skills/Data Layer/Indexing/SKILL.md +184 -0
- package/skills/Data Layer/Key-Value Store Strategy/SKILL.md +185 -0
- package/skills/Data Layer/Merge Strategy/SKILL.md +240 -0
- package/skills/Data Layer/Migration/SKILL.md +243 -0
- package/skills/Data Layer/Paging/SKILL.md +264 -0
- package/skills/Data Layer/Proto DataStore/SKILL.md +250 -0
- package/skills/Data Layer/Room/SKILL.md +244 -0
- package/skills/Data Layer/SQLite/SKILL.md +255 -0
- package/skills/Data Layer/Sync Engine/SKILL.md +268 -0
- package/skills/Dependency Injection/Dagger/SKILL.md +283 -0
- package/skills/Dependency Injection/Hilt/SKILL.md +345 -0
- package/skills/Dependency Injection/Koin/SKILL.md +282 -0
- package/skills/Developer Experience/Detekt/SKILL.md +272 -0
- package/skills/Developer Experience/Lint Rule/SKILL.md +281 -0
- package/skills/Google Ecosystem/Analytics/SKILL.md +281 -0
- package/skills/Google Ecosystem/Crashlytics/SKILL.md +234 -0
- package/skills/Google Ecosystem/Firebase/SKILL.md +200 -0
- package/skills/Google Ecosystem/Firebase Messaging/SKILL.md +266 -0
- package/skills/Media/Audio/SKILL.md +257 -0
- package/skills/Media/Camera/SKILL.md +229 -0
- package/skills/Media/CameraX/SKILL.md +295 -0
- package/skills/Media/ExoPlayer/SKILL.md +258 -0
- package/skills/Media/Video/SKILL.md +228 -0
- package/skills/Meta Skills/Domain Error Model/SKILL.md +238 -0
- package/skills/Meta Skills/Error Handling/SKILL.md +255 -0
- package/skills/Meta Skills/Error Mapping/SKILL.md +232 -0
- package/skills/Meta Skills/Failure Strategy/SKILL.md +294 -0
- package/skills/Meta Skills/Migration Strategy/SKILL.md +305 -0
- package/skills/Meta Skills/User Friendly Errors/SKILL.md +334 -0
- package/skills/Navigation/Deep Navigation/SKILL.md +209 -0
- package/skills/Navigation/Navigation/SKILL.md +215 -0
- package/skills/Navigation/Nested Navigation/SKILL.md +214 -0
- package/skills/Networking/API Contract/SKILL.md +220 -0
- package/skills/Networking/Authentication/SKILL.md +210 -0
- package/skills/Networking/Certificate Pinning/SKILL.md +167 -0
- package/skills/Networking/Fallback Strategy/SKILL.md +182 -0
- package/skills/Networking/Ktor/SKILL.md +219 -0
- package/skills/Networking/Multipart Upload/SKILL.md +213 -0
- package/skills/Networking/OkHttp/SKILL.md +193 -0
- package/skills/Networking/REST/SKILL.md +178 -0
- package/skills/Networking/Rate Limiting/SKILL.md +170 -0
- package/skills/Networking/Retrofit/SKILL.md +241 -0
- package/skills/Networking/Retry-Backoff/SKILL.md +181 -0
- package/skills/Networking/Server-Sent Events (SSE)/SKILL.md +196 -0
- package/skills/Networking/WebSocket/SKILL.md +224 -0
- package/skills/Observability/Crash Reporting/SKILL.md +219 -0
- package/skills/Observability/Logging/SKILL.md +168 -0
- package/skills/Observability/Metrics/SKILL.md +227 -0
- package/skills/Observability/Structured Logging/SKILL.md +234 -0
- package/skills/Performance/ANR Prevention/SKILL.md +192 -0
- package/skills/Performance/Allocation Optimization/SKILL.md +179 -0
- package/skills/Performance/App Startup/SKILL.md +183 -0
- package/skills/Performance/Baseline Profile/SKILL.md +205 -0
- package/skills/Performance/Battery Optimization/SKILL.md +192 -0
- package/skills/Performance/Benchmark/SKILL.md +182 -0
- package/skills/Performance/Bitmap Optimization/SKILL.md +178 -0
- package/skills/Performance/Compose Optimization/SKILL.md +187 -0
- package/skills/Performance/Heap Management/SKILL.md +184 -0
- package/skills/Performance/Macrobenchmark/SKILL.md +214 -0
- package/skills/Performance/Memory Leak Prevention/SKILL.md +218 -0
- package/skills/Performance/Rendering Performance/SKILL.md +205 -0
- package/skills/Performance/Startup Optimization/SKILL.md +219 -0
- package/skills/Security/Biometric/SKILL.md +224 -0
- package/skills/Security/Certificate Transparency/SKILL.md +158 -0
- package/skills/Security/Cryptography/SKILL.md +244 -0
- package/skills/Security/Encrypted Storage/SKILL.md +273 -0
- package/skills/Security/Frida Detection/SKILL.md +230 -0
- package/skills/Security/Hook Detection/SKILL.md +197 -0
- package/skills/Security/Keystore/SKILL.md +272 -0
- package/skills/Security/Network Security Config/SKILL.md +186 -0
- package/skills/Security/Obfuscation/SKILL.md +226 -0
- package/skills/Security/Proguard/SKILL.md +202 -0
- package/skills/Security/R8/SKILL.md +234 -0
- package/skills/Security/Reverse Engineering Resistance/SKILL.md +267 -0
- package/skills/Security/Root Detection/SKILL.md +220 -0
- package/skills/Security/Secure Networking/SKILL.md +220 -0
- package/skills/System Integration/AlarmManager/SKILL.md +182 -0
- package/skills/System Integration/App Widget/SKILL.md +182 -0
- package/skills/System Integration/Deep Link/SKILL.md +187 -0
- package/skills/System Integration/Foreground Service/SKILL.md +212 -0
- package/skills/System Integration/Notification/SKILL.md +237 -0
- package/skills/System Integration/WorkManager/SKILL.md +256 -0
- package/skills/System Integration/clipboard/SKILL.md +155 -0
- package/skills/System Integration/share-intent/SKILL.md +182 -0
- package/skills/Testing/Compose Testing/SKILL.md +296 -0
- package/skills/Testing/Espresso/SKILL.md +292 -0
- package/skills/Testing/Fake Data/SKILL.md +245 -0
- package/skills/Testing/Integration Testing/SKILL.md +288 -0
- package/skills/Testing/Mocking/SKILL.md +229 -0
- package/skills/Testing/Snapshot Testing/SKILL.md +259 -0
- package/skills/Testing/UI Testing/SKILL.md +293 -0
- package/skills/Testing/Unit Testing/SKILL.md +309 -0
- package/skills/UI System/Bottom Sheet Patterns/SKILL.md +279 -0
- package/skills/UI System/Compose/SKILL.md +296 -0
- package/skills/UI System/Compose Animation/SKILL.md +281 -0
- package/skills/UI System/Compose Multiplatform/SKILL.md +261 -0
- package/skills/UI System/Compose Navigation/SKILL.md +255 -0
- package/skills/UI System/Compose Performance/SKILL.md +274 -0
- package/skills/UI System/Design System/SKILL.md +217 -0
- package/skills/UI System/Empty State Strategy/SKILL.md +208 -0
- package/skills/UI System/Keyboard Navigation/SKILL.md +214 -0
- package/skills/UI System/Loading Strategy/SKILL.md +254 -0
- package/skills/UI System/Material 3/SKILL.md +279 -0
- package/skills/UI System/RTL/SKILL.md +179 -0
- package/src/index.ts +182 -0
- package/tsconfig.json +19 -0
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: jni
|
|
3
|
+
description: >
|
|
4
|
+
Java Native Interface (JNI) for Android — calling native C/C++ code from Kotlin.
|
|
5
|
+
Load this skill when bridging Kotlin and native code, declaring native methods,
|
|
6
|
+
handling JNI types, managing memory across the JNI boundary,
|
|
7
|
+
or passing complex objects between Kotlin and C/C++.
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# JNI
|
|
11
|
+
|
|
12
|
+
## Overview
|
|
13
|
+
JNI (Java Native Interface) is the bridge between Kotlin/Java code and native C/C++ code in Android. It allows calling C/C++ functions from Kotlin and vice versa. JNI is used for performance-critical code, hardware access, reusing existing C/C++ libraries, or code that must resist reverse engineering.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Core Principles
|
|
18
|
+
|
|
19
|
+
- **Minimize JNI boundary crossings** — each call has overhead; batch operations
|
|
20
|
+
- **JNI calls are synchronous** — run on the calling thread; use coroutines/threads on the Kotlin side
|
|
21
|
+
- **Memory is manual in native code** — no GC; always release resources
|
|
22
|
+
- **JNI types map to Java types** — `jstring` not `String`, `jint` not `Int`
|
|
23
|
+
- **Avoid storing JNI objects across calls** — use Global References when needed
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Basic Setup
|
|
28
|
+
|
|
29
|
+
```kotlin
|
|
30
|
+
// build.gradle.kts
|
|
31
|
+
android {
|
|
32
|
+
defaultConfig {
|
|
33
|
+
externalNativeBuild {
|
|
34
|
+
cmake {
|
|
35
|
+
cppFlags("-std=c++17", "-O2")
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
externalNativeBuild {
|
|
40
|
+
cmake {
|
|
41
|
+
path("src/main/cpp/CMakeLists.txt")
|
|
42
|
+
version("3.22.1")
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
```cmake
|
|
49
|
+
# src/main/cpp/CMakeLists.txt
|
|
50
|
+
cmake_minimum_required(VERSION 3.22.1)
|
|
51
|
+
project("myapp")
|
|
52
|
+
|
|
53
|
+
add_library(
|
|
54
|
+
myapp-native
|
|
55
|
+
SHARED
|
|
56
|
+
native_lib.cpp
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
find_library(log-lib log)
|
|
60
|
+
|
|
61
|
+
target_link_libraries(
|
|
62
|
+
myapp-native
|
|
63
|
+
${log-lib}
|
|
64
|
+
)
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## Declaring Native Methods
|
|
70
|
+
|
|
71
|
+
```kotlin
|
|
72
|
+
// ✅ Kotlin side — declare native functions
|
|
73
|
+
class NativeCrypto {
|
|
74
|
+
external fun encrypt(data: ByteArray, key: ByteArray): ByteArray
|
|
75
|
+
external fun decrypt(data: ByteArray, key: ByteArray): ByteArray
|
|
76
|
+
external fun generateKey(): ByteArray
|
|
77
|
+
|
|
78
|
+
companion object {
|
|
79
|
+
init {
|
|
80
|
+
System.loadLibrary("myapp-native")
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
```cpp
|
|
87
|
+
// ✅ C++ side — implement with JNI naming convention
|
|
88
|
+
// Package: com.example.app.security
|
|
89
|
+
// Class: NativeCrypto
|
|
90
|
+
// Function name format: Java_<package>_<class>_<method>
|
|
91
|
+
|
|
92
|
+
#include <jni.h>
|
|
93
|
+
#include <string>
|
|
94
|
+
|
|
95
|
+
extern "C" {
|
|
96
|
+
|
|
97
|
+
JNIEXPORT jbyteArray JNICALL
|
|
98
|
+
Java_com_example_app_security_NativeCrypto_encrypt(
|
|
99
|
+
JNIEnv* env,
|
|
100
|
+
jobject /* this */,
|
|
101
|
+
jbyteArray data,
|
|
102
|
+
jbyteArray key
|
|
103
|
+
) {
|
|
104
|
+
// Get data from Java
|
|
105
|
+
jsize dataLen = env->GetArrayLength(data);
|
|
106
|
+
jbyte* dataBytes = env->GetByteArrayElements(data, nullptr);
|
|
107
|
+
jbyte* keyBytes = env->GetByteArrayElements(key, nullptr);
|
|
108
|
+
|
|
109
|
+
// Perform encryption (simplified)
|
|
110
|
+
jbyteArray result = env->NewByteArray(dataLen);
|
|
111
|
+
jbyte* resultBytes = env->GetByteArrayElements(result, nullptr);
|
|
112
|
+
|
|
113
|
+
for (jsize i = 0; i < dataLen; i++) {
|
|
114
|
+
resultBytes[i] = dataBytes[i] ^ keyBytes[i % env->GetArrayLength(key)];
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// ✅ Always release elements
|
|
118
|
+
env->ReleaseByteArrayElements(data, dataBytes, JNI_ABORT);
|
|
119
|
+
env->ReleaseByteArrayElements(key, keyBytes, JNI_ABORT);
|
|
120
|
+
env->ReleaseByteArrayElements(result, resultBytes, 0); // 0 = copy back + free
|
|
121
|
+
|
|
122
|
+
return result;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
} // extern "C"
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
## JNI Type Mapping
|
|
131
|
+
|
|
132
|
+
| Kotlin/Java | JNI Type | Array Type |
|
|
133
|
+
|---|---|---|
|
|
134
|
+
| `Boolean` | `jboolean` | `jbooleanArray` |
|
|
135
|
+
| `Int` | `jint` | `jintArray` |
|
|
136
|
+
| `Long` | `jlong` | `jlongArray` |
|
|
137
|
+
| `Float` | `jfloat` | `jfloatArray` |
|
|
138
|
+
| `Double` | `jdouble` | `jdoubleArray` |
|
|
139
|
+
| `Byte` | `jbyte` | `jbyteArray` |
|
|
140
|
+
| `String` | `jstring` | — |
|
|
141
|
+
| `Object` | `jobject` | `jobjectArray` |
|
|
142
|
+
| `void` | `void` | — |
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## Handling Strings
|
|
147
|
+
|
|
148
|
+
```cpp
|
|
149
|
+
// ✅ Convert jstring to std::string
|
|
150
|
+
std::string jstringToString(JNIEnv* env, jstring jStr) {
|
|
151
|
+
if (jStr == nullptr) return "";
|
|
152
|
+
const char* chars = env->GetStringUTFChars(jStr, nullptr);
|
|
153
|
+
std::string result(chars);
|
|
154
|
+
env->ReleaseStringUTFChars(jStr, chars); // ✅ always release
|
|
155
|
+
return result;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// ✅ Convert std::string to jstring
|
|
159
|
+
jstring stringToJstring(JNIEnv* env, const std::string& str) {
|
|
160
|
+
return env->NewStringUTF(str.c_str());
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
JNIEXPORT jstring JNICALL
|
|
164
|
+
Java_com_example_app_NativeUtils_processText(
|
|
165
|
+
JNIEnv* env, jobject, jstring input
|
|
166
|
+
) {
|
|
167
|
+
std::string text = jstringToString(env, input);
|
|
168
|
+
std::string result = /* process */ text + "_processed";
|
|
169
|
+
return stringToJstring(env, result);
|
|
170
|
+
}
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
## Global References (Persistent JNI Objects)
|
|
176
|
+
|
|
177
|
+
```cpp
|
|
178
|
+
// ✅ Use Global Reference to hold a Java object across JNI calls
|
|
179
|
+
static jobject gCallback = nullptr;
|
|
180
|
+
|
|
181
|
+
JNIEXPORT void JNICALL
|
|
182
|
+
Java_com_example_app_NativeLib_registerCallback(
|
|
183
|
+
JNIEnv* env, jobject, jobject callback
|
|
184
|
+
) {
|
|
185
|
+
// ✅ Delete old reference if exists
|
|
186
|
+
if (gCallback != nullptr) {
|
|
187
|
+
env->DeleteGlobalRef(gCallback);
|
|
188
|
+
}
|
|
189
|
+
// ✅ Create global reference — survives across JNI calls
|
|
190
|
+
gCallback = env->NewGlobalRef(callback);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
JNIEXPORT void JNICALL
|
|
194
|
+
Java_com_example_app_NativeLib_unregisterCallback(
|
|
195
|
+
JNIEnv* env, jobject
|
|
196
|
+
) {
|
|
197
|
+
if (gCallback != nullptr) {
|
|
198
|
+
env->DeleteGlobalRef(gCallback);
|
|
199
|
+
gCallback = nullptr;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
## Calling Kotlin from C++ (Callbacks)
|
|
207
|
+
|
|
208
|
+
```cpp
|
|
209
|
+
// ✅ Call a Kotlin method from native code
|
|
210
|
+
void callKotlinCallback(JNIEnv* env, jobject callback, int progress) {
|
|
211
|
+
jclass callbackClass = env->GetObjectClass(callback);
|
|
212
|
+
|
|
213
|
+
// Find the method: void onProgress(int progress)
|
|
214
|
+
jmethodID onProgressMethod = env->GetMethodID(
|
|
215
|
+
callbackClass,
|
|
216
|
+
"onProgress",
|
|
217
|
+
"(I)V" // method signature: (int) returns void
|
|
218
|
+
);
|
|
219
|
+
|
|
220
|
+
if (onProgressMethod != nullptr) {
|
|
221
|
+
env->CallVoidMethod(callback, onProgressMethod, (jint)progress);
|
|
222
|
+
}
|
|
223
|
+
env->DeleteLocalRef(callbackClass);
|
|
224
|
+
}
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
---
|
|
228
|
+
|
|
229
|
+
## JNI Method Signatures
|
|
230
|
+
|
|
231
|
+
```
|
|
232
|
+
Type Signature
|
|
233
|
+
void V
|
|
234
|
+
boolean Z
|
|
235
|
+
byte B
|
|
236
|
+
char C
|
|
237
|
+
short S
|
|
238
|
+
int I
|
|
239
|
+
long J
|
|
240
|
+
float F
|
|
241
|
+
double D
|
|
242
|
+
String Ljava/lang/String;
|
|
243
|
+
int[] [I
|
|
244
|
+
Object Ljava/lang/Object;
|
|
245
|
+
|
|
246
|
+
Method: void foo(int, String) → (ILjava/lang/String;)V
|
|
247
|
+
Method: int bar(byte[]) → ([B)I
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
---
|
|
251
|
+
|
|
252
|
+
## Error Handling
|
|
253
|
+
|
|
254
|
+
```cpp
|
|
255
|
+
// ✅ Check for exceptions after calling Java methods
|
|
256
|
+
env->CallVoidMethod(obj, method, arg);
|
|
257
|
+
if (env->ExceptionCheck()) {
|
|
258
|
+
env->ExceptionDescribe(); // prints to logcat
|
|
259
|
+
env->ExceptionClear();
|
|
260
|
+
// handle error
|
|
261
|
+
return nullptr;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// ✅ Throw a Java exception from native code
|
|
265
|
+
void throwException(JNIEnv* env, const char* message) {
|
|
266
|
+
jclass exceptionClass = env->FindClass("java/lang/RuntimeException");
|
|
267
|
+
if (exceptionClass != nullptr) {
|
|
268
|
+
env->ThrowNew(exceptionClass, message);
|
|
269
|
+
env->DeleteLocalRef(exceptionClass);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
---
|
|
275
|
+
|
|
276
|
+
## Logging from Native Code
|
|
277
|
+
|
|
278
|
+
```cpp
|
|
279
|
+
#include <android/log.h>
|
|
280
|
+
|
|
281
|
+
#define TAG "NativeLib"
|
|
282
|
+
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__)
|
|
283
|
+
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__)
|
|
284
|
+
|
|
285
|
+
// Usage
|
|
286
|
+
LOGI("Processing %d bytes", dataLen);
|
|
287
|
+
LOGE("Encryption failed: %s", errorMsg);
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
---
|
|
291
|
+
|
|
292
|
+
## Anti-Patterns
|
|
293
|
+
|
|
294
|
+
- Not releasing `GetByteArrayElements` / `GetStringUTFChars` — memory leak
|
|
295
|
+
- Storing `JNIEnv*` across threads — `JNIEnv` is thread-local; each thread needs its own
|
|
296
|
+
- Using Local References after the JNI call returns — they become invalid
|
|
297
|
+
- Crossing the JNI boundary on every frame — batch operations; minimize round-trips
|
|
298
|
+
- Forgetting `extern "C"` in C++ files — C++ name mangling breaks JNI lookup
|
|
299
|
+
|
|
300
|
+
---
|
|
301
|
+
|
|
302
|
+
## Related Skills
|
|
303
|
+
- `ndk` — NDK build system and toolchain setup
|
|
304
|
+
- `c++` — C++ patterns for Android native code
|
|
305
|
+
- `cryptography` — using JNI for native crypto implementations
|
|
306
|
+
- `reverse-engineering-resistance` — native code as a hardening technique
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ndk
|
|
3
|
+
description: >
|
|
4
|
+
Android NDK build system, toolchain, and project setup.
|
|
5
|
+
Load this skill when configuring the NDK version, setting up CMake
|
|
6
|
+
or ndk-build, managing ABI splits, linking third-party native libraries,
|
|
7
|
+
debugging native crashes, or configuring native build flags.
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# NDK
|
|
11
|
+
|
|
12
|
+
## Overview
|
|
13
|
+
The Android NDK (Native Development Kit) provides the toolchain for compiling C/C++ code into native libraries (`.so` files) that run on Android. It includes the compiler (Clang), standard libraries, Android-specific headers, and the build system integration with Gradle via CMake or ndk-build.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Core Principles
|
|
18
|
+
|
|
19
|
+
- **Pin the NDK version** in `build.gradle.kts` — NDK updates can break builds
|
|
20
|
+
- **CMake is preferred** over ndk-build for new projects — better IDE support
|
|
21
|
+
- **ABI filters** reduce APK size — only include the ABIs your app supports
|
|
22
|
+
- **STL selection** matters — use `c++_shared` for shared libraries, `c++_static` for single `.so`
|
|
23
|
+
- **Symbols** — strip debug symbols from release builds for size; keep for crash analysis
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Gradle Setup
|
|
28
|
+
|
|
29
|
+
```kotlin
|
|
30
|
+
// app/build.gradle.kts
|
|
31
|
+
android {
|
|
32
|
+
ndkVersion = "26.1.10909125" // ✅ pin exact version
|
|
33
|
+
|
|
34
|
+
defaultConfig {
|
|
35
|
+
externalNativeBuild {
|
|
36
|
+
cmake {
|
|
37
|
+
cppFlags("-std=c++17", "-fexceptions", "-frtti")
|
|
38
|
+
arguments(
|
|
39
|
+
"-DANDROID_STL=c++_shared",
|
|
40
|
+
"-DANDROID_PLATFORM=android-26"
|
|
41
|
+
)
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// ✅ Only build for ABIs you support
|
|
46
|
+
ndk {
|
|
47
|
+
abiFilters += listOf("arm64-v8a", "x86_64") // drop x86 for production
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
externalNativeBuild {
|
|
52
|
+
cmake {
|
|
53
|
+
path("src/main/cpp/CMakeLists.txt")
|
|
54
|
+
version("3.22.1")
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// ✅ Split APKs by ABI (Play Store handles delivery)
|
|
59
|
+
splits {
|
|
60
|
+
abi {
|
|
61
|
+
isEnable = true
|
|
62
|
+
reset()
|
|
63
|
+
include("arm64-v8a", "armeabi-v7a", "x86_64")
|
|
64
|
+
isUniversalApk = false
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## CMakeLists.txt — Full Example
|
|
73
|
+
|
|
74
|
+
```cmake
|
|
75
|
+
cmake_minimum_required(VERSION 3.22.1)
|
|
76
|
+
project("myapp" VERSION 1.0.0)
|
|
77
|
+
|
|
78
|
+
# ✅ Set C++ standard
|
|
79
|
+
set(CMAKE_CXX_STANDARD 17)
|
|
80
|
+
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
|
81
|
+
|
|
82
|
+
# ✅ Source files
|
|
83
|
+
set(SOURCES
|
|
84
|
+
src/native_lib.cpp
|
|
85
|
+
src/crypto/aes_gcm.cpp
|
|
86
|
+
src/utils/string_utils.cpp
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
# ✅ Create shared library
|
|
90
|
+
add_library(myapp-native SHARED ${SOURCES})
|
|
91
|
+
|
|
92
|
+
# ✅ Find Android system libraries
|
|
93
|
+
find_library(log-lib log)
|
|
94
|
+
find_library(android-lib android)
|
|
95
|
+
|
|
96
|
+
# ✅ Include headers
|
|
97
|
+
target_include_directories(myapp-native PRIVATE
|
|
98
|
+
${CMAKE_CURRENT_SOURCE_DIR}/include
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
# ✅ Link libraries
|
|
102
|
+
target_link_libraries(myapp-native
|
|
103
|
+
${log-lib}
|
|
104
|
+
${android-lib}
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
# ✅ Compiler flags
|
|
108
|
+
target_compile_options(myapp-native PRIVATE
|
|
109
|
+
-Wall
|
|
110
|
+
-Wextra
|
|
111
|
+
-O2
|
|
112
|
+
$<$<CONFIG:Debug>:-g>
|
|
113
|
+
$<$<CONFIG:Release>:-Os -fvisibility=hidden>
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
# ✅ Strip symbols in release (reduces .so size)
|
|
117
|
+
set_target_properties(myapp-native PROPERTIES
|
|
118
|
+
$<$<CONFIG:Release>:LINK_FLAGS "-Wl,--strip-all">
|
|
119
|
+
)
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## Linking Pre-built Libraries
|
|
125
|
+
|
|
126
|
+
```cmake
|
|
127
|
+
# ✅ Link a pre-built .so from a third-party SDK
|
|
128
|
+
add_library(third-party-lib SHARED IMPORTED)
|
|
129
|
+
set_target_properties(third-party-lib PROPERTIES
|
|
130
|
+
IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/libs/${ANDROID_ABI}/libthirdparty.so
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
target_link_libraries(myapp-native
|
|
134
|
+
third-party-lib
|
|
135
|
+
${log-lib}
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
# ✅ Copy the .so to jniLibs so it's packaged in the APK
|
|
139
|
+
# Place in: src/main/jniLibs/<abi>/libthirdparty.so
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## ABI Reference
|
|
145
|
+
|
|
146
|
+
| ABI | Architecture | Notes |
|
|
147
|
+
|---|---|---|
|
|
148
|
+
| `arm64-v8a` | 64-bit ARM | Most modern Android devices |
|
|
149
|
+
| `armeabi-v7a` | 32-bit ARM | Older devices; still ~15% of installs |
|
|
150
|
+
| `x86_64` | 64-bit x86 | Emulators, some Chrome OS |
|
|
151
|
+
| `x86` | 32-bit x86 | Legacy emulators; safe to drop |
|
|
152
|
+
|
|
153
|
+
```kotlin
|
|
154
|
+
// ✅ Production — include arm64-v8a + armeabi-v7a for device coverage
|
|
155
|
+
ndk { abiFilters += listOf("arm64-v8a", "armeabi-v7a") }
|
|
156
|
+
|
|
157
|
+
// ✅ During development — add x86_64 for emulator
|
|
158
|
+
ndk { abiFilters += listOf("arm64-v8a", "armeabi-v7a", "x86_64") }
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## Debugging Native Crashes (Tombstones)
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
# ✅ Symbolicate a native crash from logcat
|
|
167
|
+
# The crash shows: #00 pc 0000abcd /data/app/.../libmyapp.so
|
|
168
|
+
|
|
169
|
+
# 1. Find your .so with debug symbols (from build/intermediates/)
|
|
170
|
+
# 2. Use ndk-stack:
|
|
171
|
+
adb logcat | ndk-stack -sym app/build/intermediates/cmake/debug/obj/arm64-v8a/
|
|
172
|
+
|
|
173
|
+
# ✅ Or use addr2line to decode a single address
|
|
174
|
+
$NDK/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-addr2line \
|
|
175
|
+
-e libmyapp.so \
|
|
176
|
+
0x0000abcd
|
|
177
|
+
|
|
178
|
+
# ✅ Use Android Studio's LLDB debugger for live native debugging
|
|
179
|
+
# Run/Debug Configurations → Debugger → Debug type: Dual
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
## Accessing Android APIs from Native Code
|
|
185
|
+
|
|
186
|
+
```cpp
|
|
187
|
+
// ✅ Android-specific native APIs
|
|
188
|
+
#include <android/asset_manager.h>
|
|
189
|
+
#include <android/asset_manager_jni.h>
|
|
190
|
+
#include <android/log.h>
|
|
191
|
+
#include <android/bitmap.h>
|
|
192
|
+
#include <GLES3/gl3.h> // OpenGL ES 3.0
|
|
193
|
+
#include <EGL/egl.h>
|
|
194
|
+
|
|
195
|
+
// ✅ Read asset from native code
|
|
196
|
+
JNIEXPORT jbyteArray JNICALL
|
|
197
|
+
Java_com_example_NativeAssets_readAsset(
|
|
198
|
+
JNIEnv* env, jobject,
|
|
199
|
+
jobject assetManager, jstring filename
|
|
200
|
+
) {
|
|
201
|
+
AAssetManager* mgr = AAssetManager_fromJava(env, assetManager);
|
|
202
|
+
const char* file = env->GetStringUTFChars(filename, nullptr);
|
|
203
|
+
|
|
204
|
+
AAsset* asset = AAssetManager_open(mgr, file, AASSET_MODE_BUFFER);
|
|
205
|
+
env->ReleaseStringUTFChars(filename, file);
|
|
206
|
+
|
|
207
|
+
if (asset == nullptr) return nullptr;
|
|
208
|
+
|
|
209
|
+
off_t size = AAsset_getLength(asset);
|
|
210
|
+
jbyteArray result = env->NewByteArray(size);
|
|
211
|
+
jbyte* buf = env->GetByteArrayElements(result, nullptr);
|
|
212
|
+
AAsset_read(asset, buf, size);
|
|
213
|
+
AAsset_close(asset);
|
|
214
|
+
|
|
215
|
+
env->ReleaseByteArrayElements(result, buf, 0);
|
|
216
|
+
return result;
|
|
217
|
+
}
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
---
|
|
221
|
+
|
|
222
|
+
## Build Variants for Native
|
|
223
|
+
|
|
224
|
+
```kotlin
|
|
225
|
+
// ✅ Different native flags per build type
|
|
226
|
+
android {
|
|
227
|
+
buildTypes {
|
|
228
|
+
debug {
|
|
229
|
+
externalNativeBuild {
|
|
230
|
+
cmake {
|
|
231
|
+
cppFlags("-DDEBUG_BUILD", "-g")
|
|
232
|
+
arguments("-DCMAKE_BUILD_TYPE=Debug")
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
release {
|
|
237
|
+
externalNativeBuild {
|
|
238
|
+
cmake {
|
|
239
|
+
cppFlags("-DNDEBUG", "-O2", "-fvisibility=hidden")
|
|
240
|
+
arguments("-DCMAKE_BUILD_TYPE=Release")
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
---
|
|
249
|
+
|
|
250
|
+
## Anti-Patterns
|
|
251
|
+
|
|
252
|
+
- Not pinning `ndkVersion` — CI builds may use different NDK than local builds
|
|
253
|
+
- Building for all 4 ABIs — `x86` is dead; `x86_64` only needed for emulators
|
|
254
|
+
- `c++_static` STL with multiple `.so` files — causes ODR violations and crashes
|
|
255
|
+
- Storing debug `.so` in the release APK — exposes symbols; strip in release
|
|
256
|
+
- Not checking `env->ExceptionCheck()` after calling back into Java — silent crashes
|
|
257
|
+
|
|
258
|
+
---
|
|
259
|
+
|
|
260
|
+
## Related Skills
|
|
261
|
+
- `jni` — JNI bridge between Kotlin and native code
|
|
262
|
+
- `c++` — C++ patterns for native Android code
|
|
263
|
+
- `gradle` — Gradle build configuration
|
|
264
|
+
- `reverse-engineering-resistance` — native code hardening
|