blinkcard / blinkcard-android

SDK for scanning and OCR of credit or payment cards. Contains native Android SDK, code samples and documentation.
44 stars 5 forks source link

Apparent theme related error on dynamic modules #20

Closed erickmartimvia closed 2 years ago

erickmartimvia commented 2 years ago

While implementing the SDK on a dynamic module (on-demand), when starting the SDK Activity, using the Built-in activities implementation, we're having the following error message:

10255-10255/com.packagename.dev E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.packagename.dev, PID: 10255
    java.lang.NoSuchFieldError: No static field colorPrimary of type I in class Lcom/microblink/blinkcard/library/R$attr; or its superclasses (declaration of 'com.microblink.blinkcard.library.R$attr' appears in /data/app/com.packagename.dev-uYC0UoSWGguzh9qeuueMQA==/split_cardscan.apk)
        at com.microblink.blinkcard.activity.BaseScanActivity.llIIlIlIIl(line:3)
        at com.microblink.blinkcard.activity.BaseScanActivity.onCreate(line:8)
        at com.microblink.blinkcard.activity.BlinkCardActivity.onCreate(line:4)
        at android.app.Activity.performCreate(Activity.java:7916)
        at android.app.Activity.performCreate(Activity.java:7903)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1307)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3285)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3459)
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83)
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2046)
        at android.os.Handler.dispatchMessage(Handler.java:107)
        at android.os.Looper.loop(Looper.java:225)
        at android.app.ActivityThread.main(ActivityThread.java:7564)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:539)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:950)

This error, in turn, crashes the Activity that initiated the SDK.

Looking into some of the SDK files, I noticed there are some references to the "colorPrimary" element on the styles:

image

I tried to implement that reference in the base app theme so it would be present on the apk, as pointed out in the message, but that didn't work. Tried to do the same in the module holding the SDK, but then I get a "manifestMerge" error, because the theme is already set on the base module manifest.

Currently looking for clues to try to get over this one, any help would be appreciated. Thanks in advance!

Environment Details

anjapenic commented 2 years ago

Hello @erickmartimvia,

Just wanted to let you know that we've forwarded this to our dev team and will get back to you as soon as we gain more info on the solution. Thanks for your patience!

Best regards, Anja

anjapenic commented 2 years ago

Hello @erickmartimvia,

Thank you for waiting for our answer!

The manifestMerge error happens because the manifest from the dynamic module gets merged into the apps manifest. Since the dynamic module depends on our SDK, the SDK’s manifest also gets merged in, and the manifest references a theme from the SDK. This can easily be bypassed by declaring the same named empty theme in the apps style file.

There is a way to make this work by using our version of integration with the RecognizerRunnerFragment as shown here - https://github.com/blinkcard/blinkcard-android#recognizerRunnerFragment.

Here’s the sample code to the activity from a dynamic module:

package com.example.blinkcard

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.microblink.blinkcard.MicroblinkSDK
import com.microblink.blinkcard.entities.recognizers.RecognizerBundle
import com.microblink.blinkcard.entities.recognizers.blinkcard.BlinkCardRecognizer
import com.microblink.blinkcard.fragment.RecognizerRunnerFragment
import com.microblink.blinkcard.fragment.overlay.ScanningOverlay
import com.microblink.blinkcard.fragment.overlay.blinkcard.BlinkCardOverlayController
import com.microblink.blinkcard.fragment.overlay.blinkcard.BlinkCardOverlaySettings
import com.microblink.blinkcard.fragment.overlay.blinkcard.scanlineui.ScanLineOverlayStrings
import com.microblink.blinkcard.fragment.overlay.blinkcard.scanlineui.ScanLineOverlayView
import com.microblink.blinkcard.intent.IntentDataTransferMode
import com.microblink.blinkcard.recognition.RecognitionSuccessType
import com.microblink.blinkcard.view.recognition.ScanResultListener
import com.microblink.sample.R

class ScanActivity : AppCompatActivity(), RecognizerRunnerFragment.ScanningOverlayBinder {

    private lateinit var recognizerBundle: RecognizerBundle

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // obtain your licence at http://microblink.com/login or contact us at http://help.microblink.com
        MicroblinkSDK.setLicenseKey(
            "set your licence key here",
            this
        )

        MicroblinkSDK.setIntentDataTransferMode(IntentDataTransferMode.PERSISTED_OPTIMISED)

        val recognizer = BlinkCardRecognizer()

        recognizerBundle = RecognizerBundle(recognizer)

        setContentView(R.layout.activity)
        val fragment = RecognizerRunnerFragment()
        fragment.recognizerRunnerView?.recognizerBundle = recognizerBundle
        supportFragmentManager.beginTransaction().replace(R.id.placeholder, fragment).commit()
    }

    override fun getScanningOverlay(): ScanningOverlay = BlinkCardOverlayController(BlinkCardOverlaySettings.Builder(recognizerBundle).build(),
    object: ScanResultListener {
        override fun onScanningDone(p0: RecognitionSuccessType) {
            finish()
        }

        override fun onUnrecoverableError(p0: Throwable) {

        }

    }, ScanLineOverlayView(true, true, ScanLineOverlayStrings.Builder(this).build(), R.style.MB_default_scan_line_overlay_style))
}

where the activity.xml file is just an empty FrameLayout

<FrameLayout android:id="@+id/placeholder"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:android="http://schemas.android.com/apk/res/android" />

Hope this helps, let us know if you have any further questions.

Best regards,

Anja

erickmartimvia commented 2 years ago

The suggested fix using the recognizerRunnerFragment approach worked just fine. Even better than using the first method!

Thanks a lot, guys, appreciate the help!!