Skip to content

Commit 61b803b

Browse files
committed
Update README.md to include a link to full documentation in the docs/ directory. Remove obsolete Kotlin compiler session file.
1 parent e319a11 commit 61b803b

14 files changed

Lines changed: 713 additions & 0 deletions

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
**StringCare Android** v5.0.0 — Compile-time obfuscation for strings and assets; runtime reveal in your app. GroupId: `dev.vyp.stringcare`.
44

5+
Full documentation is in the [docs/](docs/) directory (getting started, configuration, API, publishing, troubleshooting).
6+
57
<p align="center"><img width="10%" vspace="10" src="https://github.com/StringCare/AndroidLibrary/raw/develop/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png"></p>
68

79
<h3 align="center" style="margin-bottom:30px" vspace="20">StringCare Android Library</h3>

buildSrc/.kotlin/sessions/kotlin-compiler-15874212105837615075.salive

Whitespace-only changes.

docs/README.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# StringCare Android Documentation
2+
3+
StringCare Android provides **compile-time obfuscation** for strings and assets in your app, and **runtime reveal** via a small library. The Gradle plugin (groupId `dev.vyp.stringcare`) obfuscates resources during the build; the runtime library reveals them using the app signing certificate.
4+
5+
## Documentation index
6+
7+
- [Getting started](getting-started.md) — Quick path to your first obfuscated string (dependency, plugin, `hidden="true"`, `SC.reveal()`).
8+
- [Installation](installation.md) — Kotlin DSL, Groovy, Maven Central vs local build, and version alignment.
9+
- [Configuration](configuration.md) — The `stringcare { }` block, strings.xml attributes, and asset patterns.
10+
- [Library API](library-api.md) — Public API: `SC.init`, `SC.reveal`, `SC.obfuscate`, `Version`, `SC.Assets`, `SCTextView`, extension functions.
11+
- [Plugin tasks](plugin-tasks.md) — User-facing tasks (`stringcarePreview`, `stringcareTestObfuscate`) and variant tasks.
12+
- [Build and CI](build-and-ci.md) — Building the repo, submodule clone, and CI (checkout with submodules).
13+
- [Publishing](publishing.md) — Release workflow, secrets, and local publish (`publishToMavenLocal`).
14+
- [Migration](migration.md) — Upgrading from 4.x to 5.0 (groupId, plugin ID, package, Gradle/AGP).
15+
- [Architecture](architecture.md) — Mono-repo layout, library vs plugin, JNI, and Variant API.
16+
- [Contributing](contributing.md) — Release workflow secrets and local publish steps.
17+
- [Troubleshooting](troubleshooting.md) — Submodule, signing, plugin not found, publish job, JNI/NDK.
18+
19+
For the main project README and badges, see the [root README](../README.md).

docs/architecture.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# Architecture
2+
3+
## Repository layout
4+
5+
The project is a **mono-repo** with:
6+
7+
- **app** — Demo Android application. Applies the StringCare plugin and depends on the library. Included in the root `settings.gradle.kts` via `include(":app", ":library")`.
8+
- **library** — Android library (AAR) that provides the runtime API (`SC`, `SCTextView`, Version, Assets, etc.) and loads the native library. Built with CMake; native source lives in the **stringcare-jni** submodule.
9+
- **plugin** — Gradle plugin (JVM). Built as a **composite build**: root `settings.gradle.kts` uses `includeBuild("plugin")`, so the plugin is not a subproject but a separate build. It is applied to the app by ID `dev.vyp.stringcare.plugin`.
10+
- **stringcare-jni** — Git submodule containing the C++ implementation used by the library (and optionally by the plugin for fingerprint/signing). The library’s `CMakeLists.txt` references `../stringcare-jni/lib` for the native source.
11+
12+
## Library
13+
14+
The **library** module:
15+
16+
- Exposes the public API in package **`dev.vyp.stringcare.library`**: `SC`, `SCTextView`, `Version`, `ContextListener`, extension functions, etc.
17+
- Loads the native library **sc-native-lib** (built from **stringcare-jni**) via `System.loadLibrary("sc-native-lib")`. CMake is configured with `cmake_minimum_required` 3.22.1, C++17, and the JNI source dir set to `../stringcare-jni/lib`.
18+
- Responsibilities: **reveal** (decrypt strings and assets at runtime using the app signing certificate), **obfuscate** (encrypt strings at runtime for the same key), and **asset** access (JSON, bytes) for obfuscated assets.
19+
20+
## Plugin
21+
22+
The **plugin** module:
23+
24+
- Implements the Gradle plugin entry point **`StringCarePlugin`** (implements `Plugin<Project>`), creates the **`stringcare`** extension (`StringCareExtension`) and registers tasks.
25+
- Uses the **AGP 8.7 Variant API**: it does **not** use `BuildListener`. It uses `project.plugins.withId("com.android.application")` and then `project.extensions.getByType(AndroidComponentsExtension::class.java)` and **`onVariants`** to register per-variant tasks (e.g. `stringcareBeforeMergeResourcesDebug`, `stringcareAfterMergeResourcesDebug`, and the same for Assets). Each variant gets before/after merge tasks for resources and for assets; the “before” tasks obfuscate, the “after” tasks restore originals from backup.
26+
- Contains **JNI** (dll/dylib) in `src/main/kotlin/.../internal/jni` for development (e.g. signing/fingerprint on the host). These are packaged via `processResources` and are separate from the library’s native code (stringcare-jni).
27+
28+
## Flow
29+
30+
- **Compile time:** When you build an Android application that applies the plugin, the plugin runs before the merge of resources and assets. It backs up the configured string XML files and asset files, obfuscates them using the signing certificate fingerprint (or mocked fingerprint), and the merge steps see the obfuscated content. After the merge, the plugin restores the originals so the source tree is unchanged. The APK therefore contains obfuscated strings and assets instead of plain text.
31+
- **Runtime:** The app loads the **library** and calls `SC.init(context)`. When you call `SC.reveal(id)` or `SC.reveal(value)`, or use `SCTextView`, the library uses the same certificate (from the running app) to derive the key and decrypt the content. Obfuscation and revelation are symmetric with respect to the signing key.

docs/build-and-ci.md

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# Build and CI
2+
3+
## Building the project
4+
5+
The stringcare-android repository uses the **stringcare-jni** native library as a **Git submodule**. You must load it before building.
6+
7+
**Clone with submodules:**
8+
9+
```bash
10+
git clone --recurse-submodules <repo-url> stringcare-android
11+
cd stringcare-android
12+
```
13+
14+
**If you already cloned without submodules:**
15+
16+
```bash
17+
git submodule update --init --recursive
18+
```
19+
20+
Then build and test:
21+
22+
```bash
23+
./gradlew clean build
24+
./gradlew test
25+
```
26+
27+
To run instrumented tests (requires an emulator or device):
28+
29+
```bash
30+
./gradlew connectedCheck
31+
```
32+
33+
## Project structure
34+
35+
- **Root** — Contains `settings.gradle.kts` and `build.gradle.kts`. Includes the **app** and **library** modules.
36+
- **app** — Demo Android application; applies the StringCare plugin and depends on the library.
37+
- **library** — Android library (AAR) that provides the runtime API (`SC`, `SCTextView`, etc.) and loads the native library from **stringcare-jni** via CMake.
38+
- **plugin** — Gradle plugin (JVM); included as a **composite build** via `includeBuild("plugin")` in the root `settings.gradle.kts`, not as `include(":plugin")`. So the plugin is built from the `plugin/` directory and applied to the app by ID `dev.vyp.stringcare.plugin`.
39+
- **stringcare-jni** — Git submodule containing the native C++ code used by the library (and optionally by the plugin for signing/fingerprint). The library’s `CMakeLists.txt` points to `../stringcare-jni/lib` for the native source.
40+
41+
## CI
42+
43+
For **GitHub Actions** (or any CI), always checkout the repo **with submodules** so that the JNI code is available:
44+
45+
```yaml
46+
- uses: actions/checkout@v4
47+
with:
48+
submodules: true
49+
token: ${{ secrets.PAT }} # if the submodule is private
50+
```
51+
52+
Without `submodules: true`, the library’s CMake build will fail because the native source tree will be missing. For the release workflow and publish steps, see [Publishing](publishing.md).

docs/configuration.md

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# Configuration
2+
3+
## Plugin block
4+
5+
Configure the StringCare plugin in your app (or module) `build.gradle.kts` under the `stringcare` extension:
6+
7+
| Property | Type | Default | Description |
8+
|----------|------|---------|-------------|
9+
| `debug` | Boolean | `false` | Enable extra logging (paths, located files). |
10+
| `skip` | Boolean | `false` | Skip obfuscation (e.g. for CI or when JNI is unavailable). |
11+
| `assetsFiles` | List<String> | `[]` | Glob patterns for asset files to obfuscate (e.g. `"*.json"`). |
12+
| `stringFiles` | List<String> | e.g. `["strings.xml"]` | Names of string resource XML files to scan (e.g. `"strings.xml"`, `"strings_extra.xml"`). |
13+
| `srcFolders` | List<String> | e.g. `["src/main"]` | Source set paths relative to the module where the plugin looks for resources and assets. |
14+
| `mockedFingerprint` | String | `""` | If set, use this value instead of the real signing certificate fingerprint (e.g. for tests or when signing is not available). |
15+
16+
Example:
17+
18+
```kotlin
19+
stringcare {
20+
debug = false
21+
skip = false
22+
assetsFiles = mutableListOf("*.json")
23+
stringFiles = mutableListOf("strings.xml", "strings_extra.xml")
24+
srcFolders = mutableListOf("src/main")
25+
mockedFingerprint = ""
26+
}
27+
```
28+
29+
## Strings (strings.xml)
30+
31+
Only strings marked with `hidden="true"` are obfuscated. Other attributes are optional:
32+
33+
- **`hidden="true"`** — Include this string in obfuscation. Omit or set to `"false"` to leave it plain.
34+
- **`androidTreatment`**`"true"` (default) or `"false"`. Affects whitespace normalization when revealing; should match how you call `SC.reveal(..., androidTreatment = ...)`.
35+
- **`containsHtml`** — Set to `"true"` if the string contains HTML that should be parsed when revealing.
36+
37+
Example:
38+
39+
```xml
40+
<resources>
41+
<string name="public_label">Hello</string>
42+
<string name="api_secret" hidden="true">my-secret</string>
43+
<string name="html_content" hidden="true" containsHtml="true">&lt;b&gt;Bold&lt;/b&gt;</string>
44+
</resources>
45+
```
46+
47+
The plugin scans files matching `stringFiles` under directories matching `srcFolders` (e.g. `src/main/res/values/strings.xml`).
48+
49+
## Assets
50+
51+
Asset files are matched by the patterns in `assetsFiles` (e.g. `*.json`). The plugin looks under the paths in `srcFolders` (e.g. `src/main/assets`). Obfuscated assets are decrypted at runtime via the library. To read an obfuscated asset in code, use [Library API](library-api.md): `SC.asset().json(path)`, `SC.asset().jsonArray(path)`, or `SC.asset().bytes(path)`.

docs/contributing.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# Contributing
2+
3+
## Release workflow secrets
4+
5+
To run the **Release** workflow and publish to Maven Central (Sonatype), configure these GitHub **repository secrets**:
6+
7+
| Secret | Description |
8+
|--------|-------------|
9+
| `NEXUS_USERNAME` | Sonatype/OSSRH username |
10+
| `NEXUS_PASSWORD` | Sonatype/OSSRH password |
11+
| `GPG_KEY_ID` | GPG key ID used for signing (e.g. short key id) |
12+
| `GPG_PASSPHRASE` | Passphrase for the GPG key |
13+
| `PAT` | Personal Access Token with repo scope (for checkout and release steps) |
14+
15+
## Publishing a release
16+
17+
1. In GitHub, go to **Actions** and select the **Release** workflow.
18+
2. Run it via **Run workflow** (`workflow_dispatch`).
19+
3. Fill in the inputs: **version** (e.g. `5.0.0`), **title**, **changelog**, **issue**.
20+
4. Set **Publish Maven** to **`true`** to publish the library and plugin to Sonatype. Leave it `false` to only run the prepare and tag steps.
21+
5. The workflow will build, test, (optionally) publish both `dev.vyp.stringcare:library` and `dev.vyp.stringcare.plugin`, and create the Git tag and GitHub Release.
22+
23+
## Local publish
24+
25+
To test publishing locally without pushing to Sonatype:
26+
27+
```bash
28+
./gradlew :library:publishToMavenLocal
29+
./gradlew :plugin:publishToMavenLocal
30+
```
31+
32+
Signing is **optional** when publishing to Maven local: if the property `signing.gnupg.keyName` is not set, the build skips signing and still publishes. For publishing to Sonatype (CI or manual), signing is required.
33+
34+
For more detail on the release workflow and secrets, see the root [CONTRIBUTING.md](../CONTRIBUTING.md).

docs/getting-started.md

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
# Getting started
2+
3+
## What is StringCare
4+
5+
StringCare Android obfuscates string resources and asset files at **build time** (via a Gradle plugin) and reveals them at **runtime** in your app (via a small library). Sensitive strings never appear in plain text in your APK; the library uses the app signing certificate to derive a key and decrypt them. You add the plugin and library to your project, mark which strings and assets to obfuscate, and call `SC.reveal()` (or use `SCTextView`) where you need the plain value.
6+
7+
## Prerequisites
8+
9+
- **Gradle** 8.11 or later
10+
- **Android Gradle Plugin (AGP)** 8.7 or later
11+
- **Kotlin** 2.0 or later (or compatible Java)
12+
- **minSdk** 21 (Android 5.0) or higher
13+
- **targetSdk** 35 recommended
14+
15+
## Add the library
16+
17+
In your app module `build.gradle.kts`, add the runtime dependency:
18+
19+
```kotlin
20+
dependencies {
21+
implementation("dev.vyp.stringcare:library:5.0.0")
22+
}
23+
```
24+
25+
Use the same version as the plugin (see below). For other build systems see [Installation](installation.md).
26+
27+
## Apply the plugin
28+
29+
In your **project** `settings.gradle.kts`, ensure plugin repositories are available:
30+
31+
```kotlin
32+
pluginManagement {
33+
repositories {
34+
gradlePluginPortal()
35+
mavenCentral()
36+
google()
37+
}
38+
}
39+
```
40+
41+
In your **app** module `build.gradle.kts`, apply the plugin and add a minimal `stringcare` block:
42+
43+
```kotlin
44+
plugins {
45+
id("com.android.application")
46+
id("org.jetbrains.kotlin.android")
47+
id("dev.vyp.stringcare.plugin")
48+
}
49+
50+
stringcare {
51+
debug = false
52+
skip = false
53+
stringFiles = mutableListOf("strings.xml")
54+
srcFolders = mutableListOf("src/main")
55+
assetsFiles = mutableListOf() // add e.g. "*.json" if you obfuscate assets
56+
}
57+
```
58+
59+
## Obfuscate a string
60+
61+
1. In `res/values/strings.xml` (or a file matched by `stringFiles`), add a string and mark it for obfuscation with `hidden="true"`:
62+
63+
```xml
64+
<resources>
65+
<string name="api_key" hidden="true">my-secret-api-key</string>
66+
</resources>
67+
```
68+
69+
2. In your code, initialize StringCare with the application context (e.g. in `Application.onCreate()` or before first use):
70+
71+
```kotlin
72+
import dev.vyp.stringcare.library.SC
73+
74+
// In Application or Activity:
75+
SC.init(applicationContext)
76+
```
77+
78+
3. Reveal the string by resource ID or by value:
79+
80+
```kotlin
81+
// By resource ID (typical for strings.xml)
82+
val apiKey = SC.reveal(R.string.api_key)
83+
84+
// Or if you have the obfuscated value (e.g. from another source)
85+
val plain = SC.reveal(obfuscatedValue)
86+
```
87+
88+
The plugin will replace the plain text in `strings.xml` during the build with an obfuscated form; the library decrypts it at runtime using the app signing certificate.
89+
90+
## Run the app
91+
92+
Build and run your app as usual (`./gradlew assembleDebug` or Run from Android Studio). The first time you call `SC.reveal()`, the library uses the signing key (or the debug key when debugging) to reveal the string. Ensure you have called `SC.init(context)` before any `SC.reveal()` or `SCTextView` usage.
93+
94+
For more options (assets, `SCTextView`, versions, and full configuration), see [Configuration](configuration.md) and [Library API](library-api.md). For detailed installation variants (Groovy, local build), see [Installation](installation.md).

docs/installation.md

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
# Installation
2+
3+
## Kotlin DSL
4+
5+
1. In your **project** `settings.gradle.kts`, configure plugin repositories:
6+
7+
```kotlin
8+
pluginManagement {
9+
repositories {
10+
gradlePluginPortal()
11+
mavenCentral()
12+
google()
13+
}
14+
}
15+
```
16+
17+
2. In your **app** (or module) `build.gradle.kts`, apply the plugin and add the library:
18+
19+
```kotlin
20+
plugins {
21+
id("com.android.application")
22+
id("org.jetbrains.kotlin.android")
23+
id("dev.vyp.stringcare.plugin")
24+
}
25+
26+
dependencies {
27+
implementation("dev.vyp.stringcare:library:5.0.0")
28+
}
29+
```
30+
31+
Use the same version for both the plugin and the library (e.g. `5.0.0`). The plugin is resolved from Maven Central (or Gradle Plugin Portal) when you use the `id("dev.vyp.stringcare.plugin")` form; you can append a version in the root project with `id("dev.vyp.stringcare.plugin") version "5.0.0" apply false` and then in the app only `id("dev.vyp.stringcare.plugin")` if you use a version catalog or extra settings.
32+
33+
## Groovy
34+
35+
If you use Groovy build scripts:
36+
37+
1. In the project `build.gradle`, add the plugin to the buildscript classpath and apply it in the app module:
38+
39+
```groovy
40+
buildscript {
41+
repositories {
42+
google()
43+
mavenCentral()
44+
}
45+
dependencies {
46+
classpath 'com.android.tools.build:gradle:8.7.3'
47+
classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:2.0.21'
48+
classpath 'dev.vyp.stringcare:plugin:5.0.0'
49+
}
50+
}
51+
```
52+
53+
2. In the app `build.gradle`:
54+
55+
```groovy
56+
apply plugin: 'com.android.application'
57+
apply plugin: 'org.jetbrains.kotlin.android'
58+
apply plugin: 'dev.vyp.stringcare.plugin'
59+
60+
dependencies {
61+
implementation 'dev.vyp.stringcare:library:5.0.0'
62+
}
63+
```
64+
65+
For migration from 4.x Groovy setup, see [Migration](migration.md).
66+
67+
## Using a local build
68+
69+
To test the plugin and library from a local build of the stringcare-android repo:
70+
71+
1. **Plugin:** In your app project `settings.gradle.kts`, include the plugin as a composite build:
72+
73+
```kotlin
74+
pluginManagement {
75+
repositories {
76+
gradlePluginPortal()
77+
mavenCentral()
78+
google()
79+
}
80+
}
81+
// Path to the stringcare-android repo; adjust as needed
82+
includeBuild("../path/to/stringcare-android/plugin")
83+
```
84+
85+
Then in the app `build.gradle.kts` use `id("dev.vyp.stringcare.plugin")` without a version (the composite build supplies it).
86+
87+
2. **Library:** Either:
88+
- Publish the library to Maven local from stringcare-android: `./gradlew :library:publishToMavenLocal`, then in your app add `mavenLocal()` to repositories and `implementation("dev.vyp.stringcare:library:5.0.0")`, or
89+
- If your app is inside the same stringcare-android repo, use `implementation(project(":library"))`.
90+
91+
## Requirements
92+
93+
- **Gradle** 8.11 or later
94+
- **Android Gradle Plugin** 8.7 or later
95+
- **Kotlin** 2.0 or later (if using Kotlin)
96+
- **minSdk** 21 (Android 5.0) or higher
97+
98+
See [Getting started](getting-started.md) for a minimal walkthrough.

0 commit comments

Comments
 (0)