Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cant get the camera to open in Ionic 4 #204

Open
acndr opened this issue Oct 31, 2018 · 28 comments
Open

Cant get the camera to open in Ionic 4 #204

acndr opened this issue Oct 31, 2018 · 28 comments

Comments

@acndr
Copy link

acndr commented Oct 31, 2018

Hi all,

I am trying to use this QR scanner with an Ionic 4 project, but just cant seem to get it to open the camera. I have implemented the example as per the Ionic 4 docs (https://beta.ionicframework.com/docs/native/qr-scanner/) as here:

...
import {QRScanner, QRScannerStatus} from '@ionic-native/qr-scanner/ngx';
...

export class CardPage {

    ...

    payment() {
        console.log('Scan start');

        this.qrScanner.getStatus().then((status) => {
            console.log(status)
        });

        this.qrScanner.prepare()
            .then((status: QRScannerStatus) => {
                console.log('Scan status', status);
                if (status.authorized) {
                    // camera permission was granted


                    // start scanning
                    let scanSub = this.qrScanner.scan().subscribe((text: string) => {
                        console.log('Scanned something', text);

                        this.qrScanner.hide(); // hide camera preview
                        scanSub.unsubscribe(); // stop scanning
                    });

                    this.showCamera();

                    this.qrScanner.resumePreview();

                    // show camera preview
                    this.qrScanner.show()
                        .then((data: QRScannerStatus) => {
                            console.log('datashowing', data.showing);
                        }, err => {
                            console.log('show error', err);
                        });

                } else if (status.denied) {
                    // camera permission was permanently denied
                    // you must use QRScanner.openSettings() method to guide the user to the settings page
                    // then they can grant the permission from there
                } else {
                    // permission was denied, but not permanently. You can ask for permission again at a later time.
                }
            })
            .catch((e: any) => console.log('Scan error is', e));
    }

    showCamera() {
        (window.document.querySelector('ion-app') as HTMLElement).classList.add('cameraView');
    }

    hideCamera() {
        (window.document.querySelector('ion-app') as HTMLElement).classList.remove('cameraView');
        let content = <HTMLElement>document.getElementsByTagName("body")[0];
        content.style.background = "white !important";
    }

...

}

Which when clicking the button that fires payment() does initial give me the prompt to allow permissions for the camera, but after pressing yes nothing happens. The console logs are firing, even the one after the show() promise of console.log('datashowing', data.showing); so the function is working, but the camera just doesn't show up

I found this issue (#156 (comment)) which suggests that we need to make the ion-app element have a transparent background which I have implemented in the above code and by using inspector I can see that its being applied, but that doesn't help.

Does anyone know what is wrong?

This is happening in both Android emulator (API 26) and iOS simulator (iOS 11)

I realise this is not specifically an Ionic git repo but the Ionic docs point here.

Ionic info below

Ionic:

ionic (Ionic CLI) : 4.2.1
Ionic Framework : @ionic/angular 4.0.0-beta.12
@angular-devkit/build-angular : 0.7.5
@angular-devkit/schematics : 0.7.5
@angular/cli : 6.1.5
@ionic/angular-toolkit : 1.0.0

Cordova:

cordova (Cordova CLI) : 8.1.1 (cordova-lib@8.1.0)
Cordova Platforms : android 7.1.1, browser 5.0.4
Cordova Plugins : cordova-plugin-ionic-keyboard 2.1.3, cordova-plugin-ionic-webview 2.2.0, (and 6 other plugins)

@acndr acndr closed this as completed Oct 31, 2018
@acndr acndr reopened this Oct 31, 2018
@ireade
Copy link

ireade commented Oct 31, 2018

What CSS do you have in the .cameraView class?

The way I had to do it was to set the display to none.

const ionApp = <HTMLElement>document.getElementsByTagName('ion-app')[0];

const startScanner = () => {
            scanSub = this.qrScanner.scan().subscribe((text: string) => {
                console.log(text);
            });

            this.qrScanner.show();
            ionApp.style.display = 'none';
});

const closeScanner = () => {
            this.qrScanner.hide();
            scanSub.unsubscribe();
            ionApp.style.display = 'block';
});

@acndr
Copy link
Author

acndr commented Oct 31, 2018

@ireade Thank you that does work - you can see the camera now! However it means that we can't add any elements into the body to use as close or scan buttons, right? How did you get around that?

@ireade
Copy link

ireade commented Nov 1, 2018

@onfire Great!

Yes you're correct, this method completely hides the application so you can't add a close button. I used a timeout so the scanner automatically closes after 10 seconds, but this isn't really ideal. I'm actually currently trying to figure out a better solution, testing out hiding only part of the app instead or something like that.

@OhYuuKii
Copy link

OhYuuKii commented Nov 1, 2018

Hey ! I got the same problem, thank you for the solution ! I'm now trying to display some stuff in front of the preview. Keep me updated if you find out how !

@redbaty
Copy link

redbaty commented Nov 3, 2018

This is related to shadow DOM styling, which I just heard about on ionic v4 haha, don't know if this is the best solution but it works.

Solution 1 - Recommended

You can put this css on your component's scss.

ion-content {
  --background: none transparent;
}

Solution 2

    showCamera() {
        setTimeout(() => {
            window.document.querySelectorAll('ion-content')
                  .forEach(element => {
                      const element1 = element.shadowRoot.querySelector('style');
                      element1.innerHTML = element1.innerHTML
                                                   .replace('--background:var(--ion-background-color,#fff);', '--background: transparent');
                  });
        }, 300);
    }

    hideCamera() {
        window.document.querySelectorAll('ion-content')
              .forEach(element => {
                  const element1 = element.shadowRoot.querySelector('style');
                  element1.innerHTML = element1.innerHTML
                                               .replace('--background: transparent', '--background:var(--ion-background-color,#fff);');
              });
    }

@ireade
Copy link

ireade commented Nov 5, 2018

So I've sort of solved this. It's a bit of a hacky solution, but it works for me.

Instead of hiding the app entirely, I added a class to the html element:

const startScanner = () => {
            // Show scanner 

            const rootElement = <HTMLElement>document.getElementsByTagName('html')[0];
            rootElement.classList.add('qr-scanner-open');
});

const closeScanner = () => {
            // Hide and unsubscribe from scanner

            const rootElement = <HTMLElement>document.getElementsByTagName('html')[0];
            rootElement.classList.remove('qr-scanner-open');
});

In my HTML, I added a Close scanner button just inside the ion-content

<ion-header>
    <!-- ... -->
</ion-header>

<ion-content >
    <div id="close-scanner-button" text-center>
        <ion-button (click)="closeScanner()" color="warning">
            Close Scanner
        </ion-button>
    </div>
    
    <!-- Other content -->
</ion-content>

<ion-footer>
    <!-- ... -->
</ion-footer>

Finally, in my CSS, I hid everything on the page besides the scanner button, and changed the height of the application to be smaller and only be large enough to show the close scanner button:

#close-scanner-button {
    display: none;
}

html.qr-scanner-open {

    ion-app,
    ion-content {
        height: 70px !important;
    }

    ion-content {
        --overflow: hidden !important;
    }

    ion-header,
    ion-footer,
    ion-content > *:not(#close-scanner-button) {
        display: none;
    }

    #close-scanner-button {
        display: block;
    }
}

The result is something like this:

img_d02b4af931b3-1

@onfire @OhYuuKii

@acndr
Copy link
Author

acndr commented Nov 7, 2018

@ireade Nice work, I've just quickly tried implementing this and it's working for me too

@b1ueRa1n
Copy link

Thank you @ireade . it's Working for me too.

@lim-enhui
Copy link

@ireade Can you share me the demo file... I tried apply on 3.9.2 it failed.

@lim-enhui
Copy link

ion-content {
--background: var(--ion-background-color, transparent);
}

@MinkiPan-zz
Copy link

MinkiPan-zz commented Mar 3, 2019

Please guys, I desperately need a solution or a tutorial, how I can add an UI on top of this scanner, since I can't just show a full screen camera preview, with the hacky solution <HTMLElement>document.getElementsByTagName('ion-app')[0].style.display = none
I am sitting the whole week trying to get a QRScanner working on my ionic 4 App. :(

the solution with simply putting following code into my scss also doesn't work
ion-content { --background: none transparent; }

@lim-enhui
Copy link

Please guys, I desperately need a solution or a tutorial, how I can add an UI on top of this scanner, since I can't just show a full screen camera preview, with the hacky solution <HTMLElement>document.getElementsByTagName('ion-app')[0].style.display = none
I am sitting the whole week trying to get a QRScanner working on my ionic 4 App. :(

the solution with simply putting following code into my scss also doesn't work
ion-content { --background: none transparent; }

this is meant to put on your page.. and do not mix with the above solution... ion-app will make the whole page display none...

@MinkiPan-zz
Copy link

MinkiPan-zz commented Mar 3, 2019

@lim-enhui -enhui what do you mean with "put on your page"?
I have this in html

<ion-header>
  <ion-toolbar>
    <ion-title>qrscanner</ion-title>
  </ion-toolbar>
</ion-header>

<ion-content padding>

</ion-content>

and this in scss
ion-content { --background: none transparent; }

I don't see any camera preview

@lim-enhui
Copy link

capture
capture2
capture3

@MinkiPan-zz
Copy link

thanks! I made it work!
I am wondering if there could be a better solution than inject css at runtime to make everything transparent until CameraPreview can be seen, I have to hardcode every possible html element...

@baotpham
Copy link

baotpham commented Mar 21, 2019

Here is my solution using angular. Basically, I have a flag on ion-content to turn on and off a css class:

<ion-content [class.show-qr-scanner]="isOn">
       <-- other content here -->
</ion-content>
.show-qr-scanner {
  display: none;
}
import { Component, OnInit } from '@angular/core';

import { QRScanner, QRScannerStatus } from '@ionic-native/qr-scanner/ngx';

@Component({
  selector: 'app-qr-scanner',
  templateUrl: './qr-scanner.page.html',
  styleUrls: ['./qr-scanner.page.scss'],
})
export class QrScannerPage implements OnInit {

  isOn = false;
  scannedData: {};

  constructor(
    private qrScanner: QRScanner
  ) {
  }

  ngOnInit() {
  }

  startScanner() {

    this.qrScanner.prepare()
      .then((status: QRScannerStatus) => {
        if (status.authorized) {

          this.isOn = true;

          // start scanning
          const scanSub = this.qrScanner.scan().subscribe((text: string) => {
            console.log('Scanned something', text);

            this.isOn = false;
            this.qrScanner.hide().then();
            scanSub.unsubscribe();
          });

          this.qrScanner.show().then();


        } else if (status.denied) {
          // camera permission was permanently denied
          // you must use QRScanner.openSettings() method to guide the user to the settings page
          // then they can grant the permission from there
          this.qrScanner.openSettings();
        } else {
          // permission was denied, but not permanently. You can ask for permission again at a later time.
        }
      })
      .catch((e: any) => console.log('Error is', e));
  }

}

@devotebest
Copy link

I got same problem now.
anyone can share full source?
thank you

@redbaty
Copy link

redbaty commented May 23, 2019

@devotebest have you tried these?

#204 (comment)

@auron105
Copy link

@devotebest have you try #204 (comment) ?
it work for me

@kyrist
Copy link

kyrist commented Jul 19, 2019

This is related to shadow DOM styling, which I just heard about on ionic v4 haha, don't know if this is the best solution but it works.

Solution 1 - Recommended

You can put this css on your component's scss.

ion-content {
  --background: none transparent;
}

Solution 2

    showCamera() {
        setTimeout(() => {
            window.document.querySelectorAll('ion-content')
                  .forEach(element => {
                      const element1 = element.shadowRoot.querySelector('style');
                      element1.innerHTML = element1.innerHTML
                                                   .replace('--background:var(--ion-background-color,#fff);', '--background: transparent');
                  });
        }, 300);
    }

    hideCamera() {
        window.document.querySelectorAll('ion-content')
              .forEach(element => {
                  const element1 = element.shadowRoot.querySelector('style');
                  element1.innerHTML = element1.innerHTML
                                               .replace('--background: transparent', '--background:var(--ion-background-color,#fff);');
              });
    }

it work for me

@KenSoftDev
Copy link

I got same problem now.
anyone can share full source?
thank you

https://github.com/ken-y2017/ionic4-qrscanner

@BenjaminPiette
Copy link

BenjaminPiette commented Oct 16, 2019

<ion-content no-scroll [ngClass]="{'transparentBody':isCameraShown}">

.transparentBody {
        background: transparent none !important;
        --background: none transparent;
}

showCamera() {
        window.document.querySelector('ion-app').classList.add('transparentBody')
}

hideCamera() {
        window.document.querySelector('ion-app').classList.remove('transparentBody')
}

@Marko-Matijevic
Copy link

Hi I am also using QR Scanner. My problem is that when I navigate to other page and navigate again to the page where QR Scanner is implemented , after triggering the scan function , my qrScanner.destroy() wont remove my instance and camera works in the background.

`scan(): Promise {
let scanSub: any;
let ionApp = document.getElementsByTagName('app-root')[0];
let closeBtn = document.getElementById('close-btn');
let radar = document.getElementById('radar');

    return new Promise<any>((resolve, reject) => {

        closeBtn.style.display = 'block';
        radar.style.display = 'block';
        closeBtn.addEventListener('click', () => {
            scanSub.unsubscribe();
            ionApp.style.display = 'block';
            closeBtn.style.display = 'none';
            radar.style.display = 'none';
            this.qrScanner.hide();
            this.qrScanner.destroy();
        });

        scanSub = this.qrScanner.scan().subscribe((text: string) => {
            resolve(text);
        });

        //show camera preview
        ionApp.style.display = 'none';
        this.qrScanner.useCamera(0);
        this.qrScanner.show();
    });
}`

@jamespsterling
Copy link

I was unable to solve this with any solutions above for my Ionic v4 app. I solved it this way:

  ionViewDidEnter() {

    window.document.querySelector('#qr-scanner').shadowRoot.querySelector('main').style.background = 'transparent';
    window.document.body.style.background = 'transparent';
    const appRoot = window.document.querySelector('app-root') as HTMLElement;
    appRoot.style.background = 'transparent';
    const ionApp = window.document.querySelector('ion-app') as HTMLElement;
    ionApp.style.background = 'transparent';

    this.openQrScanner();
  }

@Sampath-Lokuge
Copy link

This works nicely for me: https://edupala.com/ionic-qr-scanner/

@severomer
Copy link

This is related to shadow DOM styling, which I just heard about on ionic v4 haha, don't know if this is the best solution but it works.

Solution 1 - Recommended

You can put this css on your component's scss.

ion-content {
  --background: none transparent;
}

Solution 2

    showCamera() {
        setTimeout(() => {
            window.document.querySelectorAll('ion-content')
                  .forEach(element => {
                      const element1 = element.shadowRoot.querySelector('style');
                      element1.innerHTML = element1.innerHTML
                                                   .replace('--background:var(--ion-background-color,#fff);', '--background: transparent');
                  });
        }, 300);
    }

    hideCamera() {
        window.document.querySelectorAll('ion-content')
              .forEach(element => {
                  const element1 = element.shadowRoot.querySelector('style');
                  element1.innerHTML = element1.innerHTML
                                               .replace('--background: transparent', '--background:var(--ion-background-color,#fff);');
              });
    }

it works :)

@NiklasMerz
Copy link

I found a quite nice solution too. You can use Angulars [class.hide]="scannerOpen" to attach a class with the background CSS var if you need it and hide elements based on that variable too.

.hide {
  --background: none transparent;
}

Template:

<ion-header [translucent]="true">
  <ion-toolbar>
    <ion-buttons slot="start">
      <ion-menu-button></ion-menu-button>
    </ion-buttons>
    <ion-title>Open</ion-title>
  </ion-toolbar>
</ion-header>

<ion-content [fullscreen]="true" [class.hide]="scannerShown">
  <ion-header collapse="condense">
    <ion-toolbar>
      <ion-title size="large">Open box</ion-title>
    </ion-toolbar>
  </ion-header>

  <div id="container" *ngIf="!scannerShown">
    <p><strong class="capitalize">Open box</strong></p>
    <ion-button (click)="scan()">
      <ion-icon name="qr-code" slot="start"></ion-icon>
      Scan QR code
    </ion-button>

    <!-- Test UI-->
    <br>
    <br>
    <p *ngIf="data">
     Scanned data is:
    </p>
    {{data}}
  </div>
</ion-content>

Page

import { Component, OnInit, ViewChild } from '@angular/core';
import { QRScanner, QRScannerStatus } from '@ionic-native/qr-scanner/ngx';
import { IonContent } from '@ionic/angular';

@Component({
  selector: 'app-login',
  templateUrl: './open.page.html',
  styleUrls: ['./open.page.scss'],
})
export class OpenPage {
  public data: string;
  public scannerShown: boolean;

  constructor(private qrScanner: QRScanner) { }


  scan() {
    // Optionally request the permission early
    this.qrScanner.prepare()
      .then((status: QRScannerStatus) => {
        console.debug(status);
        if (status.authorized) {
          // camera permission was granted


          // start scanning
          const scanSub = this.qrScanner.scan().subscribe((text: string) => {
            console.log('Scanned something', text);
            this.data = text;

            this.qrScanner.hide(); // hide camera preview
            this.scannerShown = false;
            scanSub.unsubscribe(); // stop scanning
          });
          this.qrScanner.show().then((showStatus) => console.debug('show status', showStatus)).catch((e) => console.error('show error', e));
          this.scannerShown = true;

        } else if (status.denied) {
          // camera permission was permanently denied
          // you must use QRScanner.openSettings() method to guide the user to the settings page
          // then they can grant the permission from there
        } else {
          // permission was denied, but not permanently. You can ask for permission again at a later time.
        }
      })
      .catch((e: any) => console.log('Error is', e));

  }

}

@Webiers
Copy link

Webiers commented Dec 14, 2021

mine was not visible because of DARK MODE in phone setting is enabled

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests