From f3ed3f33540a24ddf4216052c58186800e97d435 Mon Sep 17 00:00:00 2001 From: Ikromjon Ochilov Date: Sun, 4 Oct 2026 00:07:39 +0200 Subject: [PATCH] Fix the launch crash on Android under NativePHP v4 NativePHP v4 creates bridge functions on a background thread after the activity has resumed. The Scan function registered its result launcher with registerForActivityResult() in its constructor, which Android only allows before the activity is STARTED, so every v4 Android app with this plugin died at launch with an IllegalStateException. v3 creates bridge functions in onCreate and was not affected. Register with the activity's result registry directly, which is valid at any point in the lifecycle, and re-register when the activity instance changes. Reproduced and verified on an Android 16 emulator: the app crashed at launch on nativephp/mobile 4.6.0 before, and now launches on 4.6.0 and 3.3.9 and opens the scanner. --- CHANGELOG.md | 14 ++++++++++++++ .../android/src/DocumentScannerFunctions.kt | 16 ++++++++++++++-- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5781694..9e53f4d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,20 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [1.5.0-beta.2] - 2026-10-04 + +> **Pre-release.** Replaces 1.5.0-beta.1, which crashes at launch on Android under NativePHP +> Mobile v4. Scanning itself still has not been run on a physical device. Install with +> `composer require ikromjon/nativephp-mobile-document-scanner:^1.5@beta`. + +### Fixed + +- Android: the app crashed at launch on NativePHP for Mobile v4. v4 creates bridge functions + after the activity has resumed, and the scanner registered its result launcher with + `registerForActivityResult()`, which Android only allows before the activity starts. The + launcher is now registered with the activity's result registry directly, which is valid at + any point. NativePHP v3 creates bridge functions in `onCreate` and was not affected + ## [1.5.0-beta.1] - 2026-10-03 > **Pre-release.** The native fixes below compile in a NativePHP Mobile v4 app on iOS and diff --git a/resources/android/src/DocumentScannerFunctions.kt b/resources/android/src/DocumentScannerFunctions.kt index 570c2df..19ff8cb 100644 --- a/resources/android/src/DocumentScannerFunctions.kt +++ b/resources/android/src/DocumentScannerFunctions.kt @@ -23,9 +23,11 @@ import org.json.JSONArray import org.json.JSONObject import java.io.File import java.io.FileOutputStream +import java.lang.ref.WeakReference object DocumentScannerFunctions { private const val TAG = "DocumentScanner" + private const val SCAN_LAUNCHER_KEY = "com.nativephp.documentscanner.scan" private var defaultMaxPages = 0 private var defaultOutputFormat = "jpeg" @@ -36,6 +38,7 @@ object DocumentScannerFunctions { private var defaultScannerMode = "full" private var scannerLauncher: ActivityResultLauncher? = null + private var launcherOwner: WeakReference? = null private var currentOutputFormat = "jpeg" private var currentJpegQuality = 90 @@ -67,11 +70,20 @@ object DocumentScannerFunctions { } } + /** + * Registers with the activity's result registry directly rather than + * through registerForActivityResult(). That call is only legal before the + * activity is STARTED, and NativePHP v4 creates bridge functions after the + * activity has resumed, so it crashed the app at launch. + */ fun registerLauncher(activity: FragmentActivity) { - if (scannerLauncher != null) return + if (scannerLauncher != null && launcherOwner?.get() === activity) return + scannerLauncher?.unregister() + launcherOwner = WeakReference(activity) scannerLauncher = - activity.registerForActivityResult( + activity.activityResultRegistry.register( + SCAN_LAUNCHER_KEY, ActivityResultContracts.StartIntentSenderForResult(), ) { result: ActivityResult -> if (result.resultCode == Activity.RESULT_OK) {