Skip to content

Consolidate RN test app Android MRZ scanner onto shared SDK handler#1817

Merged
transphorm merged 5 commits intodevfrom
justin/kmp-consolidate-mrz-pr1
Mar 6, 2026
Merged

Consolidate RN test app Android MRZ scanner onto shared SDK handler#1817
transphorm merged 5 commits intodevfrom
justin/kmp-consolidate-mrz-pr1

Conversation

@transphorm
Copy link
Member

@transphorm transphorm commented Mar 6, 2026

This PR delivers the first-round Android MRZ consolidation in rn-sdk-test-app by replacing local parser/scanner logic with the shared SDK camera handler flow.

What changed

  • Reworked SelfMrzScannerActivity to delegate scanning and progress updates to CameraMrzBridgeHandler.scanMrzWithPreview(...).
  • Removed duplicated local parser implementation (SelfMrzParser.kt).
  • Updated Android dependency wiring in the RN test app to consume xyz.self.sdk:shared:0.1.0 and removed direct ML Kit/CameraX scanner deps from the app module (keeping camera-view as compileOnly for PreviewView).
  • Added mavenLocal() resolution for local SDK artifact testing.
  • Updated MRZ consolidation spec status and execution notes.

Scope / non-goals

  • No JS bridge contract changes (documentNumber, dateOfBirth, dateOfExpiry payload remains the same).
  • iOS MRZ consolidation remains out of scope for this PR.
  • Composite-build wiring (includeBuild("../../kmp-sdk")) remains pending as a separate follow-up.

Summary by CodeRabbit

  • Refactor

    • Rewrote Android camera and MRZ scanning to a coroutine-driven bridge scanner with JSON-based result handling; removed the previous built-in MRZ parser.
    • Adjusted Android build to enable publishing variants and removed previous manual publishing setup.
  • Bug Fixes / Chores

    • Updated Android dependencies: removed camera/ML Kit modules, added shared SDK and JSON serialization dependency, and changed camera view to compile-only.
    • CI/workflow now publishes the SDK to local Maven and added mavenLocal() to repository resolution.
  • Documentation

    • Updated project spec to reflect Android consolidation progress and pending iOS/infra work.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 6, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 76dd4d01-4b1a-48d8-a50e-bfe5ef48f9ae

📥 Commits

Reviewing files that changed from the base of the PR and between 2017457 and 087569f.

📒 Files selected for processing (1)
  • packages/rn-sdk-test-app/android/app/src/main/java/com/selfxyz/demoapp/SelfMrzScannerActivity.kt

📝 Walkthrough

Walkthrough

Consolidates MRZ scanning into the KMP SDK: removes local MRZ parser and CameraX/ML Kit integration, replaces scanning with SDK's CameraMrzBridgeHandler and coroutine-based JSON results, adds publishLibraryVariants and mavenLocal() usage, and publishes KMP SDK to mavenLocal() in CI.

Changes

Cohort / File(s) Summary
Build / Publishing
packages/kmp-sdk/shared/build.gradle.kts, .github/workflows/rn-sdk-test-app-ci.yml
Enabled Android library variant publishing via publishLibraryVariants("release"); removed manual MavenPublication; CI step added to publish the KMP SDK to mavenLocal() during Android CI.
Repository Resolution
packages/rn-sdk-test-app/android/build.gradle
Added mavenLocal() to allprojects.repositories, changing dependency resolution order for Android projects.
Android app dependencies
packages/rn-sdk-test-app/android/app/build.gradle
Removed CameraX core/camera2/lifecycle and ML Kit text-recognition; added xyz.self.sdk:shared:0.1.0 and org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.3; changed camera-view from implementation to compileOnly.
MRZ runtime integration
packages/rn-sdk-test-app/android/app/src/main/java/com/selfxyz/demoapp/SelfMrzScannerActivity.kt
Replaced local CameraX/ML Kit image-analysis with CameraMrzBridgeHandler coroutine-based scanning, JSON result parsing, explicit cancellation handling, and updated permission callback signature.
MRZ parsing removal
packages/rn-sdk-test-app/android/app/src/main/java/com/selfxyz/demoapp/SelfMrzParser.kt
Deleted the entire local MRZ parsing implementation (types, parser, detection/state logic).
Spec / Documentation
specs/projects/sdk/workstreams/rn-sdk/SPEC-MRZ-CONSOLIDATION.md
Updated status to mark Android consolidation landed, documented execution status/known limitations (use of mavenLocal()), and outlined remaining iOS/composite-build infra tasks.

Sequence Diagram(s)

sequenceDiagram
    participant Activity as SelfMrzScannerActivity
    participant Bridge as CameraMrzBridgeHandler (KMP SDK)
    participant Native as Native MRZ Engine
    Activity->>Bridge: start scan with preview
    Bridge->>Native: stream frames / analyze
    Native-->>Bridge: JSON result {documentNumber, dateOfBirth, dateOfExpiry}
    Bridge-->>Activity: progress updates / final JSON
    Activity->>Activity: parse JSON -> RESULT_OK or RESULT_CANCELED
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested labels

codex

Suggested reviewers

  • shazarre
  • remicolin
  • seshanthS

Poem

✨ Local parsers fade to one shared plan,
coroutines hum where CameraX once ran.
Gradle finds the SDK close at hand,
CI publishes so builds can stand.
A tidy merge — one SDK for the land. 🎉

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ❓ Inconclusive The description covers what changed and scope/non-goals but lacks explicit testing details and QA instructions as required by the template. Add a 'Tested' section explaining how this change was validated, and a 'How to QA' section with repeatable testing steps.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and specifically describes the main change: consolidating the RN test app's Android MRZ scanner onto the shared SDK handler.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch justin/kmp-consolidate-mrz-pr1

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 46bd3d1102

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@packages/rn-sdk-test-app/android/app/src/main/java/com/selfxyz/demoapp/SelfMrzScannerActivity.kt`:
- Around line 73-74: scanJob can race and allow scanMrzWithPreview() to set
RESULT_OK after the activity begins teardown; ensure you cancel the job on every
exit path and short-circuit the success branch by checking activity state.
Update scanMrzWithPreview() (and any callbacks that call setResult(RESULT_OK))
to first check isFinishing || isDestroyed and return early if true, and also
cancel scanJob in all exit/abort paths (not just onDestroy) so the coroutine
cannot resume and overwrite a canceled result.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 294bf37e-e521-45f8-81a2-5934144fbecb

📥 Commits

Reviewing files that changed from the base of the PR and between cde591b and 46bd3d1.

📒 Files selected for processing (6)
  • packages/kmp-sdk/shared/build.gradle.kts
  • packages/rn-sdk-test-app/android/app/build.gradle
  • packages/rn-sdk-test-app/android/app/src/main/java/com/selfxyz/demoapp/SelfMrzParser.kt
  • packages/rn-sdk-test-app/android/app/src/main/java/com/selfxyz/demoapp/SelfMrzScannerActivity.kt
  • packages/rn-sdk-test-app/android/build.gradle
  • specs/projects/sdk/workstreams/rn-sdk/SPEC-MRZ-CONSOLIDATION.md
💤 Files with no reviewable changes (1)
  • packages/rn-sdk-test-app/android/app/src/main/java/com/selfxyz/demoapp/SelfMrzParser.kt

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/rn-sdk-test-app/android/app/src/main/java/com/selfxyz/demoapp/SelfMrzScannerActivity.kt (1)

56-61: ⚠️ Potential issue | 🟠 Major

Cancel scanJob on all exit paths to prevent result race.

Both the back-press handler and cancel button call setResult(RESULT_CANCELED) + finish() but don't cancel scanJob. There's a window between finish() and onDestroy() where scanMrzWithPreview could return and overwrite the canceled result with RESULT_OK.

🔒 Proposed fix
         onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) {
             override fun handleOnBackPressed() {
+                scanJob?.cancel()
                 setResult(RESULT_CANCELED)
                 finish()
             }
         })

And for the cancel button:

         cancelButton.setOnClickListener {
+            scanJob?.cancel()
             setResult(RESULT_CANCELED)
             finish()
         }

Additionally, consider guarding the success path with an isFinishing check:

-                    if (hasResult) return@launch
+                    if (hasResult || isFinishing) return@launch

Also applies to: 184-187

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@packages/rn-sdk-test-app/android/app/src/main/java/com/selfxyz/demoapp/SelfMrzScannerActivity.kt`
around lines 56 - 61, The back-press callback and cancel button currently call
setResult(RESULT_CANCELED) + finish() but do not cancel the coroutine/job
handling the scan, causing scanJob to potentially complete later and overwrite
the result; update both the OnBackPressedCallback handler and the cancel button
click handler to cancel the scanJob (scanJob?.cancel()) before calling setResult
and finish(), and also add a guard in the success path of scanMrzWithPreview to
check activity.isFinishing (or a boolean like isFinishingGuard) before calling
setResult(RESULT_OK) to avoid overwriting a canceled result; ensure onDestroy
also cancels scanJob to cover all exit paths.
🧹 Nitpick comments (2)
specs/projects/sdk/workstreams/rn-sdk/SPEC-MRZ-CONSOLIDATION.md (1)

186-186: Minor: Consider clarifying error code test scope.

The test table shows camera.error-codes.contract as "Pass (Android)" but the description mentions it's a Unit test. If this is actually validated through manual testing or integration tests rather than unit tests, consider updating the Type column to reflect that.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@specs/projects/sdk/workstreams/rn-sdk/SPEC-MRZ-CONSOLIDATION.md` at line 186,
Update the test specification row for `camera.error-codes.contract` to
accurately reflect the test scope: change the Type column from "Unit" to the
correct test type (e.g., "Integration" or "Manual") and adjust the Pass/platform
cell if needed so it matches how the error codes were validated (e.g., "Pass
(Android) - Integration" or "Pass (Android) - Manual"); ensure the
`camera.error-codes.contract` description remains unchanged but the Type and
Pass cells clearly indicate the actual validation method.
.github/workflows/rn-sdk-test-app-ci.yml (1)

67-69: Missing Gradle caching for KMP SDK publish step.

The new publishToMavenLocal step runs without Gradle caching, which will slow down CI runs. Per coding guidelines, workflows should use .github/actions/cache-gradle for Gradle operations.

Consider adding the cache action before this step:

      - name: Cache Gradle
        uses: ./.github/actions/cache-gradle
      - name: Publish KMP SDK to mavenLocal
        run: |
          cd packages/kmp-sdk && ./gradlew :shared:publishToMavenLocal --quiet

Alternatively, if the main build step at line 70-73 already benefits from a shared Gradle daemon/cache, you could consolidate both Gradle invocations. As per coding guidelines: "Use shared composite actions in .github/actions when caching dependencies in GitHub workflows instead of calling actions/cache directly... use cache-gradle for Gradle wrappers and caches."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/rn-sdk-test-app-ci.yml around lines 67 - 69, Add Gradle
caching before the "Publish KMP SDK to mavenLocal" step: insert the existing
composite action .github/actions/cache-gradle immediately prior to the step that
runs `cd packages/kmp-sdk && ./gradlew :shared:publishToMavenLocal --quiet` (the
step named "Publish KMP SDK to mavenLocal"), or consolidate this gradle
invocation with the main build gradle step so both use the shared cache/daemon;
ensure the cache action is referenced as uses: ./.github/actions/cache-gradle so
the publishToMavenLocal step benefits from Gradle caching.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In
`@packages/rn-sdk-test-app/android/app/src/main/java/com/selfxyz/demoapp/SelfMrzScannerActivity.kt`:
- Around line 56-61: The back-press callback and cancel button currently call
setResult(RESULT_CANCELED) + finish() but do not cancel the coroutine/job
handling the scan, causing scanJob to potentially complete later and overwrite
the result; update both the OnBackPressedCallback handler and the cancel button
click handler to cancel the scanJob (scanJob?.cancel()) before calling setResult
and finish(), and also add a guard in the success path of scanMrzWithPreview to
check activity.isFinishing (or a boolean like isFinishingGuard) before calling
setResult(RESULT_OK) to avoid overwriting a canceled result; ensure onDestroy
also cancels scanJob to cover all exit paths.

---

Nitpick comments:
In @.github/workflows/rn-sdk-test-app-ci.yml:
- Around line 67-69: Add Gradle caching before the "Publish KMP SDK to
mavenLocal" step: insert the existing composite action
.github/actions/cache-gradle immediately prior to the step that runs `cd
packages/kmp-sdk && ./gradlew :shared:publishToMavenLocal --quiet` (the step
named "Publish KMP SDK to mavenLocal"), or consolidate this gradle invocation
with the main build gradle step so both use the shared cache/daemon; ensure the
cache action is referenced as uses: ./.github/actions/cache-gradle so the
publishToMavenLocal step benefits from Gradle caching.

In `@specs/projects/sdk/workstreams/rn-sdk/SPEC-MRZ-CONSOLIDATION.md`:
- Line 186: Update the test specification row for `camera.error-codes.contract`
to accurately reflect the test scope: change the Type column from "Unit" to the
correct test type (e.g., "Integration" or "Manual") and adjust the Pass/platform
cell if needed so it matches how the error codes were validated (e.g., "Pass
(Android) - Integration" or "Pass (Android) - Manual"); ensure the
`camera.error-codes.contract` description remains unchanged but the Type and
Pass cells clearly indicate the actual validation method.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 5e90d062-e723-4c1e-80fc-4a243fae95d2

📥 Commits

Reviewing files that changed from the base of the PR and between 46bd3d1 and 2017457.

📒 Files selected for processing (3)
  • .github/workflows/rn-sdk-test-app-ci.yml
  • packages/rn-sdk-test-app/android/app/src/main/java/com/selfxyz/demoapp/SelfMrzScannerActivity.kt
  • specs/projects/sdk/workstreams/rn-sdk/SPEC-MRZ-CONSOLIDATION.md

@transphorm transphorm merged commit be9f2d8 into dev Mar 6, 2026
28 checks passed
@transphorm transphorm deleted the justin/kmp-consolidate-mrz-pr1 branch March 6, 2026 18:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant