Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
749118f
Refactor migration guide and plugin configuration for StringCare: upd…
efraespada Mar 19, 2026
5cb10cb
Enhance CI workflow and plugin testing capabilities: update GitHub Ac…
efraespada Mar 19, 2026
e81dd4b
Refactor StringCare plugin architecture and enhance functionality: mi…
efraespada Mar 19, 2026
a67be87
Enhance CI workflow with performance regression checks and AGP compat…
efraespada Mar 19, 2026
7318856
Integrate OWASP Dependency Check plugin and refactor file handling in…
efraespada Mar 19, 2026
e3f5aa6
Refactor integration tests in PluginIntegrationTest.kt: enhance repos…
efraespada Mar 19, 2026
80a9f57
Update Kotlin compile options and enhance integration test compatibil…
efraespada Mar 19, 2026
865eb51
Remove obsolete native libraries and enhance obfuscation functionalit…
efraespada Mar 19, 2026
0b6ceb9
Update settings.gradle.kts to include the benchmark module: add `:ben…
efraespada Mar 19, 2026
87cb177
Enhance ObfuscationServiceTest with additional assertions: add a chec…
efraespada Mar 19, 2026
5f3424c
Update GitHub Actions workflows to enable submodule support: modify c…
efraespada Mar 19, 2026
e3c5c8f
Update submodule URL in .gitmodules and add stringcare-jni submodule:…
efraespada Mar 19, 2026
8feae7f
Update stringcare JNI distribution path and remove obsolete macOS nat…
efraespada Mar 19, 2026
01b7bf0
Update CI workflow to set Gradle version based on AGP selection: add …
efraespada Mar 19, 2026
c1b6823
Add example submodule to .gitmodules and initialize with latest commi…
efraespada Mar 19, 2026
dc963d5
Update command timeout configuration and enhance Gradle wrapper for J…
efraespada Mar 19, 2026
93860fa
Update subproject commit to indicate a dirty state: modify the subpro…
efraespada Mar 19, 2026
ca1b3e8
Update subproject commit reference in example file to latest version:…
efraespada Mar 19, 2026
1a3d213
Add Jetpack Compose support and refactor MainActivity: integrate Comp…
efraespada Mar 19, 2026
5d2a3d4
Refactor StringCarePlugin and related extensions for improved configu…
efraespada Mar 19, 2026
7a205f0
Enhance file restoration logic and improve task output tracking: refa…
efraespada Mar 19, 2026
756605c
Enhance file restoration process by adding module parameter to restor…
efraespada Mar 19, 2026
2d87c0d
Update CHANGELOG and plugin documentation to reflect improvements in …
efraespada Mar 19, 2026
c152312
Refactor obfuscation tasks and remove restore functionality: streamli…
efraespada Mar 19, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 84 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
name: CI

on:
push:
branches: [master, main]
pull_request:
branches: [master, main]

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: true
token: ${{ secrets.PAT }}

- uses: actions/setup-java@v4
with:
distribution: temurin
java-version: 17

- name: Grant execute permission for gradlew
run: chmod +x gradlew

- name: Plugin unit tests
run: ./gradlew :plugin:test :plugin:jacocoTestReport :plugin:jacocoTestCoverageVerification :plugin:detekt --no-daemon

- name: Plugin integration tests (optional)
continue-on-error: true
run: ./gradlew :plugin:integrationTest --no-daemon

- name: Sample app assembleDebug
run: ./gradlew :app:assembleDebug --no-daemon

- name: Performance non-regression check (assembleDebug)
env:
PERF_MAX_SECONDS: "240"
run: |
./gradlew :app:clean --no-daemon
./gradlew :app:assembleDebug --no-daemon
start=$(date +%s)
./gradlew :app:assembleDebug --no-daemon
end=$(date +%s)
elapsed=$((end - start))
echo "Measured assembleDebug (warm) time: ${elapsed}s"
if [ "$elapsed" -gt "$PERF_MAX_SECONDS" ]; then
echo "Performance regression: ${elapsed}s > ${PERF_MAX_SECONDS}s"
exit 1
fi

agp-compat:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
agp-version: ["8.0.2", "8.7.3", "9.0.0"]
steps:
- uses: actions/checkout@v4
with:
submodules: true
token: ${{ secrets.PAT }}

- uses: actions/setup-java@v4
with:
distribution: temurin
java-version: 17

- name: Grant execute permission for gradlew
run: chmod +x gradlew

- name: Set AGP version in version catalog
run: sed -i.bak 's/^agp = ".*"/agp = "${{ matrix.agp-version }}"/' gradle/libs.versions.toml

- name: Set Gradle version for selected AGP
run: |
if [ "${{ matrix.agp-version }}" = "9.0.0" ]; then
sed -i.bak 's#^distributionUrl=.*#distributionUrl=https\://services.gradle.org/distributions/gradle-9.1.0-bin.zip#' gradle/wrapper/gradle-wrapper.properties
else
sed -i.bak 's#^distributionUrl=.*#distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-all.zip#' gradle/wrapper/gradle-wrapper.properties
fi

- name: AGP compatibility check (assembleDebug)
run: ./gradlew :app:assembleDebug --no-daemon
3 changes: 3 additions & 0 deletions .github/workflows/copilot_commit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ jobs:
steps:
- name: Checkout Repository
uses: actions/checkout@v4
with:
submodules: true
token: ${{ secrets.PAT }}

- uses: vypdev/copilot@v2
with:
Expand Down
3 changes: 3 additions & 0 deletions .github/workflows/copilot_issue.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ jobs:
steps:
- name: Checkout Repository
uses: actions/checkout@v4
with:
submodules: true
token: ${{ secrets.PAT }}

- uses: vypdev/copilot@v2
with:
Expand Down
3 changes: 3 additions & 0 deletions .github/workflows/copilot_issue_comment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ jobs:
steps:
- name: Checkout Repository
uses: actions/checkout@v4
with:
submodules: true
token: ${{ secrets.PAT }}

- uses: vypdev/copilot@v2
with:
Expand Down
3 changes: 3 additions & 0 deletions .github/workflows/copilot_pull_request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ jobs:
steps:
- name: Checkout Repository
uses: actions/checkout@v4
with:
submodules: true
token: ${{ secrets.PAT }}

- uses: vypdev/copilot@v2
with:
Expand Down
3 changes: 3 additions & 0 deletions .github/workflows/copilot_pull_request_comment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ jobs:
steps:
- name: Checkout Repository
uses: actions/checkout@v4
with:
submodules: true
token: ${{ secrets.PAT }}

- uses: vypdev/copilot@v2
with:
Expand Down
6 changes: 6 additions & 0 deletions .github/workflows/hotfix_workflow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: true
token: ${{ secrets.PAT }}

- name: Validate inputs
env:
Expand Down Expand Up @@ -77,6 +80,9 @@ jobs:
steps:
- name: Checkout Repository
uses: actions/checkout@v4
with:
submodules: true
token: ${{ secrets.PAT }}

- name: Copilot - Create Tag
uses: vypdev/copilot@v2
Expand Down
33 changes: 33 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Manual / tag-driven publish to Maven Central (requires signing + Nexus credentials).
name: Publish

on:
workflow_dispatch:
inputs:
dry_run:
description: "If true, only build plugin (no upload)"
required: false
default: "true"

jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: true
token: ${{ secrets.PAT }}

- uses: actions/setup-java@v4
with:
distribution: temurin
java-version: 17

- name: Grant execute permission for gradlew
run: chmod +x gradlew

- name: Build plugin JAR
run: ./gradlew :plugin:jar --no-daemon

# Wire signing + publish when secrets are configured:
# ./gradlew :plugin:publishPluginPublicationToSonatypeRepository -PnexusUsername=... -PnexusPassword=...
3 changes: 3 additions & 0 deletions .github/workflows/release_workflow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,9 @@ jobs:
steps:
- name: Checkout Repository
uses: actions/checkout@v4
with:
submodules: true
token: ${{ secrets.PAT }}

- name: Copilot - Create Tag
uses: vypdev/copilot@v2
Expand Down
5 changes: 4 additions & 1 deletion .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,7 @@
# If the repo URL is not accessible, place the JNI library at stringcare-jni/ (copy from ../stringcare-android-c) or ensure library/CMakeLists.txt path is correct.
[submodule "stringcare-jni"]
path = stringcare-jni
url = git@github.com:vypdev/stringcare-android-c.git
url = https://github.com/vypdev/stringcare-android-c.git
[submodule "example"]
path = example
url = https://github.com/vypdev/stringcare-android-sample.git
46 changes: 46 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Changelog

## [Unreleased] β€” refactor / 6.x groundwork

### Added

- **Docs**: [AGP generated resources](docs/agp-generated-resources.md) β€” rationale for `addGeneratedSourceDirectory`.
- **AGP integration**: Per-variant obfuscation outputs are registered with `Sources.addGeneratedSourceDirectory` (`res` and `assets`) so merges consume `build/intermediates/stringcare/generated-*` overlays without touching `src/`.

### Changed

- **Breaking β€” build pipeline**: Removed in-place source mutation and post-merge restore. Tasks renamed to `stringcareObfuscateStringResources<Variant>` and `stringcareObfuscateAssets<Variant>`. Removed `stringcareAfterMerge*` / temp backup tree / `Restore*Task` / `RestoreFilesUseCase`.
- **Gradle**: Obfuscate tasks are cache-friendly (`@DisableCachingByDefault` removed); proper `@InputFiles` + `@OutputDirectory` boundaries.
- **Runtime behaviour**: Same APK obfuscation semantics; developer checkout and IDE always see plaintext resources in source control.

### Changed (historical notes)

- **Architecture**: Domain models under `domain.models` (with `models` typealiases for compatibility); `infrastructure` packages for parsers, Gradle wiring, crypto, filesystem; thin `ObfuscateStringsUseCase` + `ResourceRepository`.
- **XML**: SAX-first `strings.xml` parsing with DOM fallback for nested markup; `XmlAttributes` / `XmlParser` facade.
- **Tasks**: Gradle `Property` inputs on obfuscate/preview tasks.
- **AGP**: `compileOnly` for the Android Gradle Plugin dependency (provided at runtime on Android projects).
- **JAR size**: With `compileOnly` AGP, plugin JAR is ~180KB vs previous multi‑MB fat jar (verify locally with `./gradlew :plugin:jar`).
- **Gradle**: `StringCareBuildService` (shared build service) replaces mutable static state on `StringCarePlugin` for configuration and variant applicationIds.
- **Dependencies**: Removed Guava and Gson; added `kotlinx-serialization-json` for task JSON list inputs.
- **Execution**: Shell commands use `ProcessBuilder` with a 60s timeout and structured `ExecutionResult` (`Success` / `Failure` / `Timeout`).
- **Native host libs**: SHA-256 verification before `System.load`, retries, optional verbose logging tied to `debug` in tasks.
- **XML / scan**: Faster attribute iteration in `parseXML`; `walkTopDown` skips `build/`, `.gradle/`, `.git/`, `node_modules/`; `mapNotNull` for resource/asset discovery; idempotent `StringCareConfiguration.normalize()`.
- **Tooling**: Detekt + baseline, ktlint (non-failing), JaCoCo hook, Develocity build scan terms in root `settings.gradle.kts`.
- **Tests**: `ObfuscationServiceTest` (JNI roundtrip when loaded), UTF-16 / malformed XML parser cases; CI runs `jacocoTestCoverageVerification` with a low interim line threshold.

### Breaking changes

- **Task names / pipeline**: Integrations that referenced `stringcareBeforeMerge*` / `stringcareAfterMerge*` or depended on restore-side effects must use `stringcareObfuscateStringResources*` / `stringcareObfuscateAssets*` instead.
- **Internal APIs**: Static mutable state on `StringCarePlugin` (paths, temp folder, variant map) was removed in favor of `StringCareBuildService`. Any build logic or tests reaching into those internals must use task inputs / the registered build service instead.
- **Dependencies on the plugin JAR**: Guava and Gson are no longer bundled; list-style DSL fields are serialized with Kotlin serialization in task properties. Pure-Java consumers of internal packages are unsupported.

### Performance (roadmap vs previous generations)

- XML handling targets **SAX-first** parsing with DOM only when nested `<string>` markup requires it, and filesystem walks **prune** heavy directories (`build/`, `.gradle/`, `.git/`, `node_modules/`). End-to-end timings depend on project size; run `./gradlew :plugin:test` and your app’s obfuscation tasks locally to validate.

### Migration notes

- Public plugin id and DSL block name are unchanged (`dev.vyp.stringcare.plugin`, `stringcare { }`).
- If you relied on internal APIs (`StringCarePlugin.absoluteProjectPath`, etc.), migrate to the build service or task inputs only.

See [MIGRATION.md](MIGRATION.md).
76 changes: 14 additions & 62 deletions MIGRATION.md
Original file line number Diff line number Diff line change
@@ -1,72 +1,24 @@
# Migration from StringCare 4.x to 5.0
# Migration guide (5.x β†’ current refactor)

## GroupId and artifact IDs
## For consumers of the published plugin

- **Old:** `io.github.stringcare` (or `com.stringcare`)
- **New:** `dev.vyp.stringcare`

Update dependencies and plugin coordinates:

| 4.x | 5.0 |
|-----|-----|
| `io.github.stringcare:library` | `dev.vyp.stringcare:library` |
| `com.stringcare` plugin ID | `dev.vyp.stringcare.plugin` |

## Gradle (Kotlin DSL)

**Before (4.x, Groovy):**

```groovy
buildscript {
dependencies {
classpath 'com.stringcare:gradle-plugin:4.x'
}
}
apply plugin: 'com.stringcare'
dependencies {
implementation 'io.github.stringcare:library:4.x'
}
```

**After (5.0, Kotlin DSL):**
No changes are required in `build.gradle.kts` if you only use the public DSL:

```kotlin
plugins {
id("dev.vyp.stringcare.plugin")
}
dependencies {
implementation("dev.vyp.stringcare:library:5.0.0")
stringcare {
debug = true
// ...
}
```

Resolve the plugin from Maven Central or a local `includeBuild`; see [README](README.md#installation-kotlin-dsl).
## For forks or code that used internal statics

## Plugin configuration

- Extension and task names are unchanged (`stringcare { ... }`, `stringFiles`, `assetsFiles`, `srcFolders`, `debug`, `skip`).
- AGP 8.x and Gradle 8.x are required; the plugin uses the Variant API.

## Library package

- **Old:** `com.stringcare.library`
- **New:** `dev.vyp.stringcare.library`

Update imports in your app:

```kotlin
// Before
import com.stringcare.library.SC
import com.stringcare.library.SCTextView

// After
import dev.vyp.stringcare.library.SC
import dev.vyp.stringcare.library.SCTextView
```

## API compatibility

Public API (e.g. `SC.reveal()`, `SC.obfuscate()`, `SCTextView`, resources usage) is unchanged. Only package and Maven coordinates differ.
| Old | New |
|-----|-----|
| `StringCarePlugin.absoluteProjectPath` | Resolved per build via `StringCareBuildService.absoluteProjectPath()` (internal) |
| `StringCarePlugin.variantMap` | `StringCareBuildService` variant map (internal) |
| `StringCarePlugin.resetFolder()` | Test hook only: clears `StringCareSession` temp root for integration tests (no production temp backup tree) |

## Build / CI
## Native libraries

This repo uses the JNI native library as a Git submodule. Clone with `git clone --recurse-submodules` or `git submodule update --init --recursive`. In GitHub Actions use `checkout` with `submodules: true`.
When updating bundled `.dylib` / `.so` / `.dll`, refresh SHA-256 entries in `Stark.kt` (`EXPECTED_SHA256`).
13 changes: 13 additions & 0 deletions SECURITY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Security

## Native binaries

Host-side JNI libraries shipped in the plugin JAR are verified with SHA-256 before load. If you replace prebuilts, update the expected hashes in `plugin/.../internal/Stark.kt`.

## Signing fingerprints

The plugin derives keys from `signingReport` output. Treat CI logs as sensitive if debug logging prints certificate details.

## Reporting

Report security issues via the repository’s issue tracker or maintainer contact in the published POM.
18 changes: 18 additions & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.kotlin.android)
alias(libs.plugins.kotlin.compose)
id("dev.vyp.stringcare.plugin")
}

Expand Down Expand Up @@ -54,6 +55,14 @@ android {
jvmTarget = "17"
}

buildFeatures {
compose = true
}

androidResources {
noCompress += "json"
}

packaging {
resources {
excludes += "/META-INF/{AL2.0,LGPL2.1}"
Expand All @@ -67,6 +76,15 @@ dependencies {
exclude(group = "com.android.support", module = "support-annotations")
}
implementation(libs.androidx.appcompat)
implementation(libs.androidx.core)
implementation(libs.androidx.lifecycle.runtime.ktx)
implementation(libs.androidx.activity.compose)
implementation(platform(libs.androidx.compose.bom))
implementation(libs.androidx.compose.ui)
implementation(libs.androidx.compose.ui.graphics)
implementation(libs.androidx.compose.ui.tooling.preview)
implementation(libs.androidx.compose.material3)
debugImplementation("androidx.compose.ui:ui-tooling")
testImplementation("junit:junit:4.13.2")
implementation("org.jetbrains.kotlin:kotlin-stdlib:${libs.versions.kotlin.get()}")
implementation("commons-io:commons-io:2.15.1")
Expand Down
Loading
Loading