How to show a video from gallery in Ionic iOS - ios

I am using html5's video tag to show a video I select from the gallery. I'm getting an issue where the video doesn't load even though I've provided a source.
This is an Ionic/Angular project with Capacitor as the bridge, but still using Cordova plugins. Here is a prototype of my code:
my-page.page.ts
import { Camera, CameraOptions } from '#ionic-native/camera/ngx';
import { Capacitor } from '#capacitor/core';
#Component({...})
export class MyPage {
// ... some code which gets the a reference to the video element from the template
// this function is called when the user clicks a button to choose video from gallery
onPickVideo() {
const cameraOptions: CameraOptions = {
destinationType: this.camera.DestinationType.NATIVE_URI,
sourceType: this.camera.PictureSourceType.SAVEDPHOTOALBUM,
mediaType: this.camera.MediaType.VIDEO,
};
this.camera.getPicture(cameraOptions).then(videoUri => {
console.log(videoUri);
this.videoSrc = Capacitor.convertFileSrc(videoUri);
console.log(this.videoSrc);
this.videoEl.load();
this.videoEl.currentTime = 0.1;
});
}
}
my-page.page.html
<video playsinline #video>
<source [src]=".videoSrc" type="video/mp4" />
Your browser does not support the video tag.
</video>
The output of my-page.page.ts is:
file:///private/var/mobile/Containers/Data/Application/7D85727C-CE9A-4816-BC42-C97F03AFDEB4/tmp/F6DCE819-ED4A-41E4-BAFB-814500F2FB27.MOV
capacitor://localhost/_capacitor_file_/private/var/mobile/Containers/Data/Application/7D85727C-CE9A-4816-BC42-C97F03AFDEB4/tmp/F6DCE819-ED4A-41E4-BAFB-814500F2FB27.MOV
This works on desktop and on Android. It's not working on iPhone 6 with iOS 12. Untested on other iOS versions.
Some things I've tried:
Added NSCameraUsageDescription, NSPhotoLibraryUsageDescription, NSPhotoLibraryAddUsageDescription, NSMicrophoneUsageDescription
Used [src]= in the video tag, and removed the source tag. Or omitting the 'video/mp4' type
Running in live reload mode vs just building.
Chopping 'file:///' off the start of videoUri before passing it to convertFileSrc(). Or doing the former and directly setting it to videoSrc without using convertFileSrc() at all.

Solved by "sanitizing" the URL. I'm yet to learn what that really means. Here is the code in case anyone needs it
import { Camera, CameraOptions } from '#ionic-native/camera/ngx';
import { Capacitor } from '#capacitor/core';
import { DomSanitizer, SafeUrl } from '#angular/platform-browser';
#Component({...})
export class MyPage {
// ... some code which gets the a reference to the video element from the template
safeUrl: SafeUrl;
constructor(private sanitizer: DomSanitizer) {}
// this function is called when the user clicks a button to choose video from gallery
onPickVideo() {
const cameraOptions: CameraOptions = {
destinationType: this.camera.DestinationType.NATIVE_URI,
sourceType: this.camera.PictureSourceType.SAVEDPHOTOALBUM,
mediaType: this.camera.MediaType.VIDEO,
};
this.camera.getPicture(cameraOptions).then(videoUri => {
this.safeUrl = this.sanitizer.bypassSecurityTrustUrl(
Capacitor.convertFileSrc(videoUri)
);
this.videoEl.load();
this.videoEl.currentTime = 0.1;
});
}
}
Then make sure to be using safeUrl in the template [src]="safeUrl".

Related

How to add an audio file to React konva?

I am trying to make a site like office 365 PowerPoint. I started using React konva. I got stucked on adding audio file to konva stage with new layer. I searched alot butcan't found solution. I should be able to add an audio file and adjust its volume.
You don't need react-konva for that. react-konva can be used to visualize your page.
For the sound, you can just create <audio /> element outside of canvas <Stage/> and controls its volume.
const Audio = ({ src, isPlaying }) => {
const audioRef = React.useRef(null);
React.useEffect(() => {
if (isPlaying) {
audioRef.current.play();
} else {
audioRef.current.pause();
}
});
return <audio src={src} ref={audioRef} />;
};

Ionic4 camera plugin - cordova not avaliable on device?

I am working on an Ionic4 app which needs to be able to take a photo.
I added "cordova-plugin-camera". When i run a function of this plugin on real DEVICE to take photo, i get an error "cordova_not_avaliable".
(Note that OTHER native cordova plugins work just fine - even in same page / module).
I followed basic installation process on Ionic documentation for "cordova-plugin-camera". No other errors are thrown.
import { Component, OnInit } from '#angular/core';
import { Camera, CameraOptions } from '#ionic-native/camera/ngx';
#Component({
selector: 'app-picture',
templateUrl: './picture.page.html',
styleUrls: ['./picture.page.scss'],
})
export class PicturePage implements OnInit {
options: CameraOptions = {
quality: 100,
destinationType: this.camera.DestinationType.FILE_URI,
encodingType: this.camera.EncodingType.JPEG,
mediaType: this.camera.MediaType.PICTURE
}
constructor(private camera: Camera) { }
ngOnInit() {}
takePicture() {
this.camera.getPicture(this.options).then((imageData) => {
let base64Image = 'data:image/jpeg;base64,' + imageData;
// this.presentAlert('success');
}, (err) => {
// this.presentAlert(err); // Displays "cordova_not_avaliable"
// (For show on DEVICE. I know rest logic of alert is missing)
});
}
}
I would expect that cordova IS avaliable since it is running on an android Device. No other error is present (Also note that I get an exact same result on ionic serve).
Edit: "Also note i am not very experienced yet in this environments so i might be missing something obvious."
Edit: "title (removed preview)"
Found solution, In my camera options I was missing a
sourceType: this.camera.PictureSourceType.CAMERA
That solved the problem.

Ionic cordova-plugin-qrscanner has no camera preview

I run a simple demo to use cordova-plugin-qrscanner, it can scan qrcode but no camera preview.
qrscannerDemo on Github
Related code blow:
import { Component } from '#angular/core';
import { NavController } from 'ionic-angular';
import { AndroidPermissions } from '#ionic-native/android-permissions';
import { QRScanner, QRScannerStatus } from '#ionic-native/qr-scanner';
#Component({
selector: 'page-home',
templateUrl: 'home.html'
})
export class HomePage {
constructor(public navCtrl: NavController,
public androidPermissions: AndroidPermissions,
public qrScanner: QRScanner) {
}
qrscanner() {
// Optionally request the permission early
this.qrScanner.prepare()
.then((status: QRScannerStatus) => {
if (status.authorized) {
// camera permission was granted
alert('authorized');
// start scanning
let scanSub = this.qrScanner.scan().subscribe((text: string) => {
console.log('Scanned something', text);
alert(text);
this.qrScanner.hide(); // hide camera preview
scanSub.unsubscribe(); // stop scanning
});
this.qrScanner.resumePreview();
// show camera preview
this.qrScanner.show();
// wait for user to scan something, then the observable callback will be called
} else if (status.denied) {
alert('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.
alert('else');
}
})
.catch((e: any) => {
alert('Error is' + e);
});
}
}
<ion-header>
<ion-navbar transparent>
<ion-title>
Ionic Blank
</ion-title>
</ion-navbar>
</ion-header>
<ion-content padding style="background: none transparent;">
<button ion-button (click)="qrscanner()">qrscanner</button>
</ion-content>
I run the ionic project on android then click the button but nothing happened and no camera preview show.
I test the project again and find it can scan qrcode and get the result test, but no camera preview.
I search the problem, someone says should to set the body and any elements transparent. I try but does not work.
Android. Nothing appears on screen. #35
AnyOne help?
In top level index.html:
<ion-app style="background: none transparent;"></ion-app>
In camera display page html file:
<ion-content style="background: none transparent;">
After some research even i found the answer and surely this works fantastic for all ,but #nokeieng answer helped me too..
1) First, make a new component for qrscanner. In ionic there is a lifecycle in ionic so go according to that after entering the component this event trigger ionViewDidEnter().In this event the camera opens and let you scan.
ionViewDidEnter(){
this.qrScanner.prepare()
.then((status: QRScannerStatus) => {
if (status.authorized) {
// camera permission was granted
var camtoast = this.toastCtrl.create({
message: 'camera permission granted',
duration: 1000
});
camtoast.present();
// start scanning
this.qrScanner.show()
window.document.querySelector('ion-app').classList.add('cameraView');
let scanSub = this.qrScanner.scan().subscribe((text: string) => {
console.log('Scanned something', text);
window.document.querySelector('ion-app').classList.remove('cameraView');
this.qrScanner.hide(); // hide camera preview
const toast = this.toastCtrl.create({
message: 'You scanned text is this :'+text,
duration: 6000
});
toast.present();
scanSub.unsubscribe(); // stop scanning
});
} else if (status.denied) {
const toast = this.toastCtrl.create({
message: 'camera permission was denied',
duration: 3000
});
toast.present();
// 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 {
const toast = this.toastCtrl.create({
message: 'You can ask for permission again at a later time.',
duration: 3000
});
toast.present();
// permission was denied, but not permanently. You can ask for permission again at a later time.
}
})
.catch((e: any) => console.log('Error is', e));
}
2) After this remove the camera class when back button is pressed for that add this code.
ionViewWillLeave() will triggers when component is destroyed or left.
ionViewWillLeave(){
window.document.querySelector('ion-app').classList.remove('cameraView');
}
3) We are done with .ts file. Now we have to make the component and the main element i.e ion-app transparent so that we can see the camera for that we add this css inside theme/variables.scss
ion-app.cameraView ion-nav{opacity:0}
and
ion-app.cameraView,ion-app.cameraView ion-content,ion-app.cameraView .nav-decor,{
background: transparent url("../../assets/imgs/camera_overlay.png") !important;
background-size: 100% 100% !important;}
4) As you can see I have given a background image so that we get a camera overlay preview
and you are done with the code just run this command in terminal to see live changes in ionic
ionic cordova run android --livereload
You just need to toggle the ion-app display between "none" and "block" if the status is authorized.
const ionApp = <HTMLElement>document.getElementsByTagName("ion-app")[0];
// start scanning
const scanSub = this.qrScanner.scan().subscribe((link: string) => {
ionApp.style.display = "block";
this.qrScanner.hide(); // hide camera preview
scanSub.unsubscribe(); // stop scanning
});
ionApp.style.display = "none";
this.qrScanner.show();
There is a div, with class=“nav-decor”, which has a black background, this needs to be changed to transparent.
I changed 3 things to transparent for the camera to show: ion-app, ion-content and .nav-decor
My solution was to have a “cameraView” class, which would set the ion-app, ion-content and .nav-decor to have a transparent background.
I used this CSS
ion-app.cameraView, ion-app.cameraView ion-content, ion-app.cameraView .nav-decor {
background: transparent none !important;
}
And then these functions to show the camera after qrScanner.show() and hide it after I’m finished scanning
showCamera() {
(window.document.querySelector('ion-app') as HTMLElement).classList.add('cameraView');
}
hideCamera() {
(window.document.querySelector('ion-app') as HTMLElement).classList.remove('cameraView');
}
I've work around following many answers,
Here is my solution combined all of the answer I've read.
In my scss file named page-scan.scss
page-scan {}
ion-app.cameraView,
ion-app.cameraView ion-content,
ion-app.cameraView .nav-decor,
ion-header,
ion-navbar,
ion-title {
background: transparent none !important;
}
ion-app.cameraView {
background-size: 100% 100% !important;
/* To show image border */
background-image: url([YOU CAN USE BASE64 image here!!]) !important;
}
Note: image border like this one
Here is the sample image:
file scan.html
<ion-header>
<ion-navbar color="primary_dark">
<ion-title>scan</ion-title>
</ion-navbar>
</ion-header>
<ion-content>
</ion-content>
file scan.ts. add these functions to show and hide camera preview
private showCamera() {
((<any>window).document.querySelector('ion-app') as HTMLElement).classList.add('cameraView');
}
private hideCamera() {
((<any>window).document.querySelector('ion-app') as HTMLElement).classList.remove('cameraView');
}
And finally, call show, scan and preview camera like code below
this.showCamera();
this.qrScanner.show()
this.subScan = this.qrScanner.scan()
See issue on github here
Update your cordova-android.
I fixed this when updated to cordova android 10.1.0
cordova platform remove android
cordova platform add android#10.1.0
.ion-page{display:none important!}

mobile app for interacting with camera with html5?

I want to develop a mobile app for image capturing with camera, initially i wanted to use phonegap and tried downloading and installing the cordovastarter template for my visual studio2010, but all the versiosn of phonegap are giving me the error...'the project type is not supported by this installation' so want to drop the idea of using phonegap, so the next thing is, is it possible to interact with camera using by using only html5 without the help of phonegap?
note:im using mvc3 framework
its very much posible to interact with the camera using HTML5 media API, but the support is not yet confirmed. Hence, might not work as you'd expect:
HTML part:
<video id="video" width="640" height="480" autoplay></video>
<button id="snap">Snap Photo</button>
<canvas id="canvas" width="640" height="480"></canvas>
and the javascript goes like this:
// Put event listeners into place
window.addEventListener("DOMContentLoaded", function() {
// Grab elements, create settings, etc.
var canvas = document.getElementById("canvas"),
context = canvas.getContext("2d"),
video = document.getElementById("video"),
videoObj = { "video": true },
errBack = function(error) {
console.log("Video capture error: ", error.code);
};
// Put video listeners into place
if(navigator.getUserMedia) { // Standard
navigator.getUserMedia(videoObj, function(stream) {
video.src = stream;
video.play();
}, errBack);
} else if(navigator.webkitGetUserMedia) { // WebKit-prefixed
navigator.webkitGetUserMedia(videoObj, function(stream){
video.src = window.webkitURL.createObjectURL(stream);
video.play();
}, errBack);
}}, false);
Hope it helps, source here.

iOS app freezes, not crashing when loading video in webview

I have an iPad app developed using a 3rd party tool called OpenPlug which converts AS3 to C++ and from there on exports to iOS. (Just wanted to note this is not a "native" app using Obj-C in XCode written by me, I wrote AS3)
Now I have this iPad application which displays pictures and video in a slideshow. For the video I'm using a WebView which loads a HTML page where I change the src property of the video object to the location of the video file which was downloaded to my application storage. This is working fine except that the application freezes when it is running for a few hours (3-6).
I searched for this problem and tried the solution in iOS Safari memory leak when loading/unloading HTML5 <video> but that does not seem to change anything for me.
Since the application freezes (right before the HTML page needs to load a video) and does not crash what does that mean? Do I need to destroy the video object? First I was creating a new WebView for each video but now I'm reusing the webview and just changing the src property but that also does not help me.
Can anyone shed some light on this? OpenPlug has discontinued it service and does not offer any support anymore but nevertheless I think it is more of a webview/video problem on iPad (?)
Important to note: The application is freezing but my iPad is not. The application does not generate a crash report and does not execute any code anymore (also no traces). When I push the Home button on my iPad and press the app icon then the application is restarted.
Here is the code of my HTML page which is refreshed every time a new video needs to start (webview.location = ...)
<html>
<head>
<script>
function videoEndedHandler(){
var video = document.getElementById("videoPlayer");
video.src = "";
video.load();
window.location.hash = "ended";
}
function videoErrorHandler(){
window.location.hash = "error";
var video = document.getElementById("videoPlayer");
video.src = "";
video.load();
}
var loop;
function setup(){
var video = document.getElementById("videoPlayer");
video.addEventListener("error", videoErrorHandler,false);
video.addEventListener("ended", videoEndedHandler,false);
video.load();
video.play();
startHashLoop();
}
function startHashLoop(){
if(window.location.hash == "#touched"){
setAsPaused();
}
if(window.location.hash == "#paused"){
//check image
testImage("shouldResume.png?nocache=" + Math.random());
}
if(window.location.hash == "#resume"){
var video = document.getElementById("videoPlayer");
video.play();
}
loop = setTimeout(hashLoop,500);
}
function testImage(url) {
var img = new Image;
img.addEventListener("load",isGood);
img.addEventListener("error",isBad);
img.src = url;
}
function isGood() {
window.location.hash = "resume";
}
function isBad() {
//alert("Image does not exist");
}
function hashLoop(){
startHashLoop();
}
function setAsTouched(){
window.location.hash = "touched";
}
function setAsPaused(){
var video = document.getElementById("videoPlayer");
video.pause();
window.location.hash = "paused";
}
</script>
</head>
<body onload="setup();" style="background-color:#000000;">
<video id="videoPlayer" style="top:0;left:0;position:absolute;" width="100%" height="100%" preload="auto" src="##VIDEO_URL##" autoplay="autoplay" webkit-playsinline />
</body>
</html>
It would be helpful if you'd post your entire code, but I think it's freezing because you're loading a video from web in your main thread, which is also responsible for redrawing UI. By loading a large video inside your thread, your UI freezes as well.
I would recommend moving the code that does video loading into a separate thread (use blocks if you're on iOS5).

Resources