I have a web based application which is written with Js and Angular and has ipa and apk distribution.
We can download the apk files from Chrome but we are having problems with device's own browsers, such as Samsung browser. When we change the settings on the device to allow the download, then it sometimes downloads the file but sometimes does not. What can be the reason of this problem? I'm sharing the download function below.
Thanks in advance for the answers.
this.versionService
.getVersionFile(
versionId,
deviceInfo.device.brand,
deviceInfo.device.model,
deviceInfo.os.name,
deviceInfo.device.type,
deviceInfo.os.version,
headers
)
.subscribe(
(res) => {
const file = new File([res], `${filepath.split('/')[filepath.split('/').length - 1]}`, {});
FileSaver.saveAs(file);
this.downloadLoading = false;
this.enabledScroll();
},
(err) => {
console.log(err);
this.messageService.add({
severity: 'error',
summary: this.translate.instant('main.error'),
});
this.downloadLoading = false;
this.enabledScroll();
}
);
Related
I'm using the Web Share API to share pdf files generated with jspdf.
It works as expected for browsers such as Chrome and Edge (Desktop and Mobile) but I can't get it working on Opera for Android. When calling the navigator.share() method, the share options hub is being displayed, but there seems to be no file to be shared. On WhatsApp I get an error saying that I can't send an empty message and on other apps it just shares the title, but I'm not getting any console error.
Here's my code:
var pdf = new File([doc.output('blob')], doc_name + ".pdf", { type: "application/pdf" }); //Blob generated with jspdf
var filesToShare = [pdf];
if (navigator.canShare && navigator.canShare({ files: filesToShare })) {
try {
if (filesToShare != null)
navigator.share({ title: doc_name + ".pdf", files: filesToShare });
} catch (error) {
console.error(error.message);
}
}
I've tried sharing just text and it is working fine, I'm only facing this problem when sharing files.
As per CanIUse and MDN the feature is supported on Opera Android since v54, and I'm using v73 so I must be missing something.
In my Nuxt PWA I have a function that converts my HTML to Canvas using this package. The generated image is in base 64. Now I want to be able to share that image via: Whatsapp, Facebook, email, Instagram etc. I have found several packages but they all don't seem to support sharing files only URLs and Text.
This is my share function:
shareTicket(index) {
html2canvas(this.$refs['ticket-' + index][0], {
backgroundColor: '#efefef',
useCORS: true, // if the contents of screenshots, there are images, there may be a case of cross-domain, add this parameter, the cross-domain file to solve the problem
}).then((canvas) => {
let url = canvas.toDataURL('image/png') // finally produced image url
if (navigator.share) {
navigator.share({
title: 'Title to be shared',
text: 'Text to be shared',
url: this.url,
})
}
})
When I take out the if (navigator.share) condition I get an error in my console that navigator.share is not a function. I read somewhere that it only works on HTTPS so I uploaded to my staging server and tried but still got the same error.
Just to be clear I want to be able to share the generated image itself and not a URL.
Tell me if this URL works for you: https://nuxt-share-social-media.netlify.app
If it does, you can find the Github repo here: https://github.com/kissu/so-share-image-bounty
The code is
<template>
<div>
<div id="capture" ref="element" style="padding: 10px; background: #f5da55">
<h4 style="color: #000">Hello world!</h4>
</div>
<br />
<br />
<button #click="share">share please</button>
</div>
</template>
<script>
import html2canvas from 'html2canvas'
export default {
methods: {
share() {
// iife here
;(async () => {
if (!('share' in navigator)) {
return
}
// `element` is the HTML element you want to share.
// `backgroundColor` is the desired background color.
const canvas = await html2canvas(this.$refs.element)
canvas.toBlob(async (blob) => {
// Even if you want to share just one file you need to
// send them as an array of files.
const files = [new File([blob], 'image.png', { type: blob.type })]
const shareData = {
text: 'Some text',
title: 'Some title',
files,
}
if (navigator.canShare(shareData)) {
try {
await navigator.share(shareData)
} catch (err) {
if (err.name !== 'AbortError') {
console.error(err.name, err.message)
}
}
} else {
console.warn('Sharing not supported', shareData)
}
})
})()
},
},
}
</script>
Inspired from #denvercoder9!
More info about the answer
I've used an IIFE because I was not sure how the whole thing works, but it's works great in a method context!
I've added a missing async because ESlint and in case you wanted to make something after
I've used $refs because this is how you should select specific parts of the DOM in the Vue ecosystem
I've striped some things to keep it simple, hosted on Netlify to have some simple HTTPS and tested it on Chrome (v91), working perfectly fine!
Here is the link again to the MDN documentation of the Web Share API.
Compatibility
This is my experience for the browsers (tested on the MDN example and on my app, exact same results)
where
working
iPad chrome
yes
iPad firefox
yes
iPad safari
yes
windows chrome
yes
windows firefox
no
android chrome
yes
android firefox
no
desktop linux chrome
no
desktop linux firefox
no
For me, this was a mobile only feature (like for Android). But it looks like even some desktop browsers are handling this too. I have to admit that I was really surprised to even see this one work on Windows.
Here is an interesting post from Google that correlates this compatibility: https://web.dev/web-share/#browser-support
Reading MDN again, it says
The navigator.share() method of the Web Share API invokes the native sharing mechanism of the device.
So, I guess that the "(desktop) device" mostly do not support the Share API.
TLDR: this is working totally as intended but the compatibility is really subpar so far.
I have a variation of the code below in a share() function in an app of mine and it works fine if executed on the client.
const share = async() => {
if (!('share' in navigator)) {
return;
}
// `element` is the HTML element you want to share.
// `backgroundColor` is the desired background color.
const canvas = await html2canvas(element, {
backgroundColor,
});
canvas.toBlob(async (blob) => {
// Even if you want to share just one file you need to
// send them as an array of files.
const files = [new File([blob], 'image.png', { type: blob.type })];
const shareData = {
text: 'Some text',
title: 'Some title',
files,
};
if (navigator.canShare(shareData)) {
try {
await navigator.share(shareData);
} catch (err) {
if (err.name !== 'AbortError') {
console.error(err.name, err.message);
}
}
} else {
console.warn('Sharing not supported', shareData);
}
});
};
I am using MediaDevices: devicechange event in my react application. On local machin all working good but when i deployed application on server (ubuntu) it gives me the following error
The only difference is OS on local machine I use windows but server is ubuntu.
Here is my function
export function useDevices() {
const [devices, setDevices] = useState<MediaDeviceInfo[]>([]);
useEffect(() => {
const getDevices = () => navigator.mediaDevices.enumerateDevices().then(devices => setDevices(devices));
navigator.mediaDevices.addEventListener('devicechange', getDevices);
getDevices();
return () => {
navigator.mediaDevices.removeEventListener('devicechange', getDevices);
};
}, []);
return devices;
}
Thanks in advance.
I found the answer here getUserMedia() is no longer supported in chrome browser over http:// (Unsecure Origin) , It will work on https:// (Secure Origin)
For testing purposes, You can run chrome with the --unsafely-treat-insecure-origin-as- for this, you need to visit this link in chrome chrome://flags/#unsafely-treat-insecure-origin-as-secure and enable the option, add your site URL in the text area, and relaunch the browser. Now you should able to use getmediadevices method.
I'm hoping to migrate from using WebUSB to SerialAPI (which is explained nicely here).
Current Code:
try {
let device = await navigator.usb.requestDevice({
filters: [{
usbVendorId: RECEIVER_VENDOR_ID
}]
})
this.connect(device)
} catch (error) {
console.log(DEVICE_NAME + ': Permission Denied')
}
New Code:
try {
let device = await navigator.serial.requestPort({
filters: [{
usbVendorId: RECEIVER_VENDOR_ID
}]
})
this.connect(device)
} catch (error) {
console.log(DEVICE_NAME + ': Permission Denied')
}
The new code appears to work, but I think it's because the browser has already requested the device via the old code.
I've tried restarting Chrome as well as clearing all of the browsing history. Even closed the USB-claiming page and claimed the device with another app (during which it returns the DOMException: Unable to claim interface error), but Chrome doesn't seem to want to ask again. It just happily streams the data with the previous connection.
My hope was that using SerialAPI would be a way to avoid fighting over the USB with other processes, or at least losing to them.
Update
I had forgotten about:
Failed to execute 'requestPort' on 'Serial': "Must be handling a user gesture to show a permission request"
Does this mean that the user will need to use a button to connect to the device via SerialUSB? I think with WebUSB I was able to make the connect window automatically pop up.
For both APIs, as is noted in the update, a user gesture is required in order to call the requestDevice() or requestPort() method. It is not possible to automatically pop up this prompt. (If there is that's a bug so please let the Chrome team know so we can fix it.)
Permissions granted to a site through the WebUSB API and Web Serial API are currently tracked separately so permission to access a device through one will not automatically translate into the other.
There is not currently a way to programatically forget a device permission. That would require the navigator.permissions.revoke() method which has been abandoned. You can however manually revoke permission to access the device by clicking on the "lock" icon in the address bar while visiting the site or going to chrome://settings/content/usbDevices (for USB devices) and chrome://settings/content/serialPorts (for serial ports).
To get Chrome to "forget" the WebUSB device previously paired via navigator.usb.requestDevice API:
Open the page paired to the device you want to forget
Click on the icon in the address bar
Click x next to device. If nothing is listed, then there are no paired devices for this web page.
The new code was NOT working. It just appeared to be because Chrome was already paired with the port via the old code. There is no way the "new code" could have worked because, as noted in Kalido's comment, the SerialAPI (due to its power) requires a user gesture to connect.
The code I'm using to actually connect and get data is basically built up from a few pieces from the above links in the OP:
navigator.serial.addEventListener('connect', e => {
// Add |e.target| to the UI or automatically connect.
console.log("connected");
});
navigator.serial.addEventListener('disconnect', e => {
// Remove |e.target| from the UI. If the device was open the disconnection can
// also be observed as a stream error.
console.log("disconnected");
});
console.log(navigator.serial);
document.addEventListener('DOMContentLoaded', async () => {
const connectButton = document.querySelector('#connect') as HTMLInputElement;
if (connectButton) {
connectButton.addEventListener('click', async () => {
try {
// Request Keiser Receiver from the user.
const port = await navigator.serial.requestPort({
filters: [{ usbVendorId: 0x2341, usbProductId: not_required }]
});
try {
// Open and begin reading.
await port.open({ baudRate: 115200 });
} catch (e) {
console.log(e);
}
while (port.readable) {
const reader = port.readable.getReader();
try {
while (true) {
const { value, done } = await reader.read();
if (done) {
// Allow the serial port to be closed later.
reader.releaseLock();
break;
}
if (value) {
console.log(value);
}
}
} catch (error) {
// TODO: Handle non-fatal read error.
console.log(error);
}
}
} catch (e) {
console.log("Permission to access a device was denied implicitly or explicitly by the user.");
console.log(e);
console.log(port);
}
}
}
The device-specific Vendor and Product IDs would obviously change from device to device. In the above example I have inserted an Arduino vendor ID.
It doesn't answer the question of how to get Chrome to "forget", but I'm not sure if that's relevant when using SerialAPI because of the required gesture.
Hopefully someone with more experience will be able to post a more informative answer.
I'm am attempting to record audio using Ionic and ngCordova.
Here is my code:
$scope.captureAudio = function() {
var options = { limit: 3, duration: 10 };
$cordovaCapture.captureAudio(options).then(function(audioData) {
// Success! Audio data is here
alert(audioData);
console.log(audioData);
}, function(err) {
// An error occurred. Show a message to the user
alert(err);
});
};
When I run this in the emulator it works fine and brings up the voice recorder and when the recording is done it logs out the audioData.
When I upload it to ionic view and run it I get nothing. Not even an error.
Has anyone seen anything like this before ?
Thanks
Kevin
$cordovaCapture plugin is not yet supported by ionic view.
Please see the list of supported plugins in this link.
You can run the code in device directly using run command.
ionic run android