phonegap / phonegap-plugin-barcodescanner

cross-platform BarcodeScanner for Cordova / PhoneGap
MIT License
1.27k stars 1.41k forks source link

Cancelling barcodescanner returns two pages back on Android Oreo #717

Closed gelodeesy closed 4 years ago

gelodeesy commented 6 years ago

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

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

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

nomanbiniqbal commented 5 years ago

it happins to me as well on ioinic 4

SamuelMichelRiad commented 5 years ago

Any workarounds available?

swapnilp0x00 commented 5 years ago

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.

SamuelMichelRiad commented 5 years ago

Any workarounds for non-Ionic scenarios?

instyo commented 5 years ago

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

haimlankry commented 5 years ago

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; } }

Fever905 commented 5 years ago

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

stale[bot] commented 5 years ago

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.

Johann-S commented 5 years ago

not fixed

JoaquinTR commented 5 years ago

any fix ?

techman84 commented 5 years ago

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...
});
WilloneLim commented 5 years ago

Is there any fix/solution for this?

setoba1192 commented 4 years ago

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):

  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.

willqz commented 4 years ago

None of the suggestions work for me. =(

Has anyone solved this?

davidquon commented 4 years ago

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?

DenHerrRing commented 4 years ago

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;
    }
}
nasaleanhorea commented 4 years ago

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.

willqz commented 4 years ago

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

JoaquinTR commented 4 years ago

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.

willderazevedo commented 4 years ago

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

imarquezc commented 4 years ago

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

willderazevedo commented 4 years ago

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

imarquezc commented 4 years ago

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

pbakondy commented 4 years ago

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);
    });
}
hoango7604 commented 4 years ago

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

Pratikshakhandagale commented 4 years ago

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();
        }
      }
    });
  }
stale[bot] commented 4 years ago

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.

lock[bot] commented 4 years ago

This thread has been automatically locked.