Paper Receipt Android SDK 2.5.1
2.5.1 builds on 2.5.0 and pairs with Activation SDK 1.3.1. Its headline changes:
- Activation SDK
1.3.1. If you use Activation, your app now starts the Activation client itself with the user's privacy choices. - Sharper line items after a capture. Camera frames picked up after the shutter no longer garble line-item names.
- Holding frame analysis during photo review. A new
RecognizerView.holdFrameAnalysisAfterCapture(true)for screens that show the captured photo before scanning continues. - Capture and OCR fixes. A captured photo always reaches the recognizer, and queued camera frames are no longer overwritten.
If you use the Activation SDK, this release contains a breaking change: you must call ActivationClient.initialize(privacy) in Application.onCreate(). See Breaking changes. Apps that don't use Activation need no code changes.
Installation
Bump the BOM to 2.5.1. If you also use the Activation SDK, bump its BOM to 1.3.1 at the same time. The two are released as a pair (see the Android SDK Version Matrix).
dependencies {
implementation(platform("com.microblink.blinkreceipt:blinkreceipt-bom:2.5.1"))
implementation("com.microblink.blinkreceipt:blinkreceipt-recognizer")
implementation("com.microblink.blinkreceipt:blinkreceipt-camera-ui")
// Only if you use Activation
implementation(platform("com.actualplatform:activation-bom:1.3.1"))
implementation("com.actualplatform:activation")
}
The build requirements are unchanged from 2.5.0: compileSdk 37 (or higher) and minSdk 24. Your app's targetSdk does not need to change. As with every release, recompile your app against the new version.
The SDK ships its own consumer ProGuard/R8 rules and is safe under R8 full mode.
Breaking changes
Activation: initialize the client with the user's privacy values
This applies only if your app uses the Activation SDK. Activation SDK 1.3.1 no longer creates its client on first access. Call ActivationClient.initialize(Privacy(...)) in Application.onCreate(). Reading ActivationClient.instance before that call throws.
- Kotlin
- Java
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
ActivationClient.initialize(
Privacy(
sellOrShareStatus = ConsentState.UNKNOWN, // replace with the user's answers
personalizationStatus = ConsentState.UNKNOWN,
disclosureVersion = null,
rdpOwner = RdpOwner.ACTUAL,
)
)
BlinkReceiptSdk.initialize(this, initializeCallback)
}
}
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
ActivationClient.initialize(new Privacy(
ConsentState.UNKNOWN, // sellOrShareStatus
ConsentState.UNKNOWN, // personalizationStatus
null, // disclosureVersion
RdpOwner.ACTUAL // rdpOwner
));
BlinkReceiptSdk.initialize(this, initializeCallback);
}
}
- Order doesn't matter. Call the two
initializemethods in either order. Once both SDKs have started, the Paper Receipt SDK gives the Activation client its device and user identity, and does so again for a client created afterclose(). - Nothing crashes if you skip it. Until the client is initialized, Activation stays off and the Paper Receipt SDK logs one error. Scanning keeps working without Activation.
- Choosing the values. See the Activation 1.3.1 release notes and Android Ad Consent, including how to choose
rdpOwner.
What's new
Holding frame analysis while a captured photo is reviewed
takePicture() now pauses the analysis frames that feed the recognizer at the shutter. By default RecognizerView resumes them as soon as the photo has been handed to OCR and to your CameraCaptureListener. That suits a screen that returns straight to live scanning, and needs no code change.
If your screen shows the captured photo for the user to review before scanning continues, turn on holdFrameAnalysisAfterCapture(true) during setup. It is off by default. Frames then stay paused after a capture until you call resumeFrameAnalysis(), either after a retake or once the user is back to live scanning. Without it, frames picked up while the camera drifts during the review can outvote the photo and garble line-item names.
recognizerView.recognizerCallback(cameraRecognizerCallback);
recognizerView.cameraCaptureListener(cameraCaptureListener);
// Only if you show the captured photo for review.
recognizerView.holdFrameAnalysisAfterCapture(true);
// Later, when the user retakes or returns to live scanning:
recognizerView.resumeFrameAnalysis();
A capture that fails resumes frames either way, and is reported through CameraRecognizerCallback.onException(). The bundled camera UI turns this on for you. See Reviewing a Captured Photo in the integration guide.
CameraView gains the matching public suspendFrameAnalysis() and resumeFrameAnalysis(), and the protected isFrameAnalysisSuspended() and onCaptureFailed().
Merchant-detection signals reach Activation
ScanResults.merchantDetection(), added in 2.5.0, is now forwarded to the Activation SDK. This includes the Trip Resolution signals. A misidentified merchant on an Activation scan can now be traced to the detector responsible. It requires Activation SDK 1.3.0, and needs no code change.
Changed
CameraView.captureImage()pauses analysis frames at the shutter.onImageCaptured()is unaffected and the camera stays bound.RecognizerViewresumes frames as described in Holding frame analysis, so apps that useRecognizerView, directly or through the bundled camera UI, need no change. A capture that fails also resumes frames, and is reported throughonError(), whichRecognizerViewforwards toCameraRecognizerCallback.onException(). Only an app that subclassesCameraViewitself keeps frames paused afteronImageCaptured(), and resumes them withresumeFrameAnalysis().
Fixed
- Line-item names could be garbled when the camera moved after a capture. Analysis frames kept flowing into OCR while the user reviewed the photo. Because line items are resolved by a vote across frames, blurry frames picked up while the phone was lowered could outvote the capture, turning "Purchase" into "Burchase". Prices were unaffected, because they are checked against the receipt totals. Frame delivery now follows the scan phase, and the camera is released once a non-Activation scan finishes. A direct
RecognizerViewintegration with its own photo-review screen gets the same protection by turning onholdFrameAnalysisAfterCapture(true). - A captured photo could be discarded before reaching OCR. When a sharper preview frame was already waiting, the photo the user took could be dropped. A capture now always replaces the waiting frame, and a later preview frame never replaces a capture.
- Camera frames could be overwritten while waiting for OCR. At some device orientations, the next frame overwrote the pixels of a frame that was still waiting to be read. At other orientations, every frame caused an extra full-size bitmap allocation. Both are fixed.
- The inverted-text OCR retry sent a downscaled image to remote OCR. When OCR ran remotely, the retry uploaded a 600px image instead of the full-resolution frame. It now downscales only for on-device OCR. An on-device frame that can't be read at all now returns an empty result instead of
null. CameraView.captureImage()no longer throws when called before the camera has started. The failure is reported throughonError()instead. Before, it was thrown to the caller, where it could cancel a Flow collector for the rest of the screen's life.
Known issues
Receipt data extraction is unchanged from 2.5.0, so the 2.5.0 known issues still apply.
Upgrade checklist
- Bump the Paper Receipt BOM to
2.5.1. If you use Activation, bump the Activation BOM to1.3.1too. - If you use Activation, call
ActivationClient.initialize(privacy)inApplication.onCreate(), and follow the Activation 1.3.1 upgrade checklist. - If you use
RecognizerViewand show the captured photo for review, callholdFrameAnalysisAfterCapture(true)during setup andresumeFrameAnalysis()when the user returns to live scanning. - If you subclass
CameraView, callresumeFrameAnalysis()once you are back to live preview after a capture.