Phonegap-plugin-barcodescanner: Cancelling barcodescanner returns two pages back on Android Oreo

Created on 18 Sep 2018  路  28Comments  路  Source: phonegap/phonegap-plugin-barcodescanner

Expected Behaviour

When barcodescanner is cancelled, the display should go back to the previous page and close the scanner

Actual Behaviour

When user taps back on Android Oreo, the app goes two pages back and not on the previous page

Reproduce Scenario (including but not limited to)

Only happens on Android Oreo

Steps to Reproduce

  • Open QR scanner
  • Cancel the scan via back button
  • Observe app after cancel

Platform and Version (eg. Android 5.0 or iOS 9.2.1)

Android 8.0

(Android) What device vendor (e.g. Samsung, HTC, Sony...)

Samsung Galaxy S8

Cordova CLI version and cordova platform version

cordova --version - 8.0.0
cordova platforms - Installed platforms:

android 6.3.0

Plugin version

cordova plugin version | grep phonegap-plugin-barcodescanner

  • phonegap-plugin-barcodescanner 8.0.0 "BarcodeScanner"

Sample Code that illustrates the problem

this.barcodeScanner.scan({orientation : "portrait"}).then((imageData) => {
if (!imageData.cancelled) {
this.processImageData(imageData);
} else {
this.toastCtrl.create({ message: 'Cancelling scan...', duration: 2000 }).present();
this.disable = false;
return;
}
});

Logs taken while reproducing problem

stale

Most helpful comment

Workaround for Ionic 5

import { BarcodeScannerOptions, BarcodeScanner } from '@ionic-native/barcode-scanner/ngx';
import { Subscription } from 'rxjs';

private preventBack: Subscription;

scan() {
    this.preventBack = this.platform.backButton.subscribeWithPriority(9999, () => {});
    this.barcodeScanner.scan(this.barcodeScannerOptions).then((barcodeData) => {
        console.log(barcodeData);
        if (barcodeData.cancelled) {
            return;
        }
        // process result here

    }, (err) => {
        console.error(err);
    }).finally(() => {
        window.setTimeout(() => {
            this.preventBack.unsubscribe();
        }, 1000);
    });
}

All 28 comments

it happins to me as well on ioinic 4

Any workarounds available?

This is the work around i came up with.

In scanner page

ionViewCanLeave() {
    let canGoBack = this.canGoBackService.getValue();
    this.canGoBackService.setValue(true);
    return canGoBack;
  }

And in cancellation of scan block i wrote

if(barcodeData.cancelled) {
 if(this.platform.is('android'))
          this.canGoBackService.setValue(false);
}

Dedicated service to maintain the boolean.

import { Injectable } from '@angular/core';
@Injectable()
export class CanGoBackService {
    private canGoBack = true;
    constructor() {}

  public setValue(value: boolean) {
    this.canGoBack = value;
  }

  public getValue(): boolean {
    return this.canGoBack;
  } 
}

And before all the transition from scan page i had manually set boolean to true.

this.canGoBackService.setValue(true);
this.nav.push(MyPage)

This worked fine for me.
Still trying to find out better way.

Any workarounds for non-Ionic scenarios?

this what i did,

create

private preventBack: any;

then in scanner page put this code

ionViewDidEnter() {
if (this.preventBack) {
this.preventBack();
}
this.preventBack = this.platform.registerBackButtonAction(null);
}

ionViewWillLeave() {
if (this.preventBack) {
this.preventBack();
this.preventBack = null;
}
}

got it from : http://www.damirscorner.com/blog/posts/20170929-HandlingHardwareBackButtonInIonic.html

hope this helps

If someone is still facing this (with android 9 and barcode scanner) I managed to by pass it by registering a "backbutton" event listener when a cancel is received, and release the event listener after a second. My handler for the "backbutton" dosen't do anything, it just returns false, so the navigation doesn't happens. This listener is working on android only, which is good for this problem.

So just call the following "blockBack" function, when getting a "cancel" from the barcode plugin.

function blockBack(){

// stop back button (for 1 s)
// used by barcode camera (when canceling and returnin back)
// was sending the back event to the router, and left the screen

document.addEventListener("backbutton", onBackKeyDown, false);

setTimeout(function(){
document.removeEventListener("backbutton", onBackKeyDown, false)
}, 1000)

function onBackKeyDown() {
// swallow the back button - do nothing
return false;
}
}

Awesome, I actually just trapped the back button and made it into my "home" button! Thanks for the tip!

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

not fixed

any fix ?

My solution:

Globally in the page load:

var backButtonOff = false;
document.addEventListener('deviceready', function () {
    document.addEventListener('backbutton', function () {
        if (!backButtonOff) {
            window.history.back();
        }
    }, false);
}, false);

When the barcode scanner is triggered:

backButtonOff = true;
cordova.plugins.barcodeScanner.scan(function (result) {
    setTimeout(function(){
        backButtonOff = false;
    }, 1000);

    // processing the cancel event or the captured barcode here...
});

Is there any fix/solution for this?

My solution for this issue:

In the root page:

scanCode(anyValue): void {

        this.navCtrl.push(BarcodeEscannerPage, {
            object: anyValue,
            callback: this.handleChildPage
        });
    }

    handleChildPage(text: string, object: any): void {

        if (text.length == 0)
            return;

    }

I created a Page for handle the Scanner (BarcodeScannerPage):

```typescript
private callback: Function;
private object : any;

constructor(public navCtrl: NavController, public navParams: NavParams, private barcodeScanner: BarcodeScanner) {

this.object = navParams.get('object');
this.callback = navParams.get('callback');

}

ionViewDidLoad() {

this.initScan();

}

initScan(){
this.barcodeScanner
.scan({ prompt: 'Coloque el c贸digo a leer en el 谩rea permitida' })
.then(barcodeData => {

            if(barcodeData.cancelled){
      return this.returnData('', this.object);
    }

            this.returnData(barcodeData.text, this.object);

        })
        .catch(err => {
            console.error("Error", err);
        });

}

returnData(text: string, object :any): void {
this.callback(text, object);
this.navCtrl.pop();
}
```
I hope that it helps.

None of the suggestions work for me. =(

Has anyone solved this?

Is this a problem only on Android Oreo? If so is it a problem with Ionic/Cordova handling the back button properly rather than just with this plugin?

On Ionic 4 with Angular and Android 10 you can use this in ScanPage:

export class ScanPage implements OnInit {
    canGoBack: boolean = true;
    constructor() {}
    onClickScan() {
        this.canGoBack = false;
        this.barcodeScanner.scan()
        .then(barcodeData => {
            console.log('Barcode data', barcodeData);
            this.canGoBack = true;
        }).catch(err => {
            this.canGoBack = true;
            console.log('Error', err);
        });
    }

    ngOnChanges() {
        return this.canGoBack;
    }
}

I've tried to override the device's back button from the Ionic way:
`` this.platform.backButton.subscribe(() => { code here } or JS way: document.addEventListener('backbutton', () => { ```

neither of these were able to stop the app from navigating twice ..

btw @DenHerrRing the ionViewCanLeave() lifecycle hook has been removed since Ionic 4 , so it's not a viable solution.

Please fix this , it's very annoying.

Is this a problem only on Android Oreo? If so is it a problem with Ionic/Cordova handling the back button properly rather than just with this plugin?

yes, only android Oreo

I had this problem using Angular/typescpript with Ionic 4 and deploying to Android. While i was testing the barcode i noticed that if i call the barcode (which would open the camera) inside a modal, pressing the hardware backbutton would cause the barcode camera screen AND the modal to close, imagine that. I could not found a way to fix it, i had to use a workaround. I have no idea if it was a problem with ionic/angular/typescript, but my guess is that the barcode screen captures the hardware backbutton event AND propagates (or does not consume it, i dont know) to the ionic app, forcing the modal to close. My workaround is simple, i want to scan an ean13 code, so i created a modal, with no HTML or CSS but the needed to make it completely transparent. Inside the modal i call the barcode scanner, obtain the data and call the dismiss on the modal controller sending the code scanned from the barcode. Doing this, i can use the onDidDismiss event of the modal that "wraps" the barcode scanner to obtain the code, when it dismiss, but, when the barcode is closed via the hardware backbutton it closes the empty transparent wrapper modal, maintaining the behavior of the app. I hope this helps in anyway possible.

Solution:

  1. Create a service that import bar scanner
    service

  2. Import service on app.modules.ts Providers

  3. On back button method subscriber add this "if"
    backbutton

  4. Be happy =D

I'm trying to override backbutton behavior, but I can't make it work.. Any suggestions?

    this.platform.backButton.subscribe((event: Event) => {
      console.log(event);
    });

with that code I can see the event on my logs when pressing the backbutton, but the app is still navigating back twice.

Please help

@imarquezc , you creating the subscriber in app.components.ts, or in another page ?

@willderazevedo I was creating it in another page. Finally I was able to fix this using @instyo 's solution. Thanks for the replay anyways!

Workaround for Ionic 5

import { BarcodeScannerOptions, BarcodeScanner } from '@ionic-native/barcode-scanner/ngx';
import { Subscription } from 'rxjs';

private preventBack: Subscription;

scan() {
    this.preventBack = this.platform.backButton.subscribeWithPriority(9999, () => {});
    this.barcodeScanner.scan(this.barcodeScannerOptions).then((barcodeData) => {
        console.log(barcodeData);
        if (barcodeData.cancelled) {
            return;
        }
        // process result here

    }, (err) => {
        console.error(err);
    }).finally(() => {
        window.setTimeout(() => {
            this.preventBack.unsubscribe();
        }, 1000);
    });
}

Have the same issue and @pbakondy workaround suit me the best!

Below solution is work for me for ionic 5.2.3 馃憤

Check Barcode cancelled action and add flag in localstorage. Check below code

 this.barcodeScanner.scan().then((result) => {
    if (result.cancelled) {
        this.storeData();
    }
});

async storeData(){
    await localStorage.setItem('scanCancelled', 'true');
}

Write code in app.component.ts file :
async handleBackPress() { this.backBtnPress = this.platform.backButton.subscribeWithPriority(100, () => { let flag = localStorage.getItem('scanCancelled'); if (flag === 'true') { localStorage.setItem('scanCancelled', 'false'); return; } else { if (this.router.url === '/events') { if (this.backPress) { navigator['app'].exitApp(); } else { this.commonTask.translateToastMsg('Press back again to exit App', 'info'); this.backPress = true; setTimeout(function () { this.backPress = false; }, 1000); } } else { this.nav.pop(); } } }); }

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

This thread has been automatically locked.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

HallmediaDigital picture HallmediaDigital  路  4Comments

camilonos77 picture camilonos77  路  7Comments

McOffsky picture McOffsky  路  7Comments

Bajranghudda1 picture Bajranghudda1  路  4Comments

justinhenricks picture justinhenricks  路  5Comments