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.
Related
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();
}
);
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'm trying to get to work PDF support detection based on a browser where application is running.
First application is checking if a browser is not running on a mobile device. That part works fine - I'm getting Globals.bAllowPdfPreview = true
Then I try to execute code below
if (Globals.bAllowPdfPreview && window.navigator && window.navigator.mimeTypes)
{
Globals.bAllowPdfPreview = !!_.find(window.navigator.mimeTypes, function (oType) {
return oType && 'application/pdf' === oType.type;
});
if (!Globals.bAllowPdfPreview)
{
Globals.bAllowPdfPreview = (typeof window.navigator.mimeTypes['application/pdf'] !== 'undefined');
}
}
It works fine on Chrome but I'm not able to get it to work on FireFox or IE11 - it fails on both statements to verify.
Any tips why is not working?
It came up that Firefox is not working as Mozilla removed the application/pdf MIME type from navigator.mimeTypes object and for IE11 only application/futuresplash and application/x-shockwave-flash are available by default.
I am trying to add pictures in a mail body by adding them to the attachments of the mail item and then adding the sources with the right content id in the html of the mail body.
This is working fine except with Outlook for Mac. In Outlook for Windows and also in the browsers (even safari) the pictures are inserted correctly.
In Outlook for Mac I get blank squares with an error that the file might be moved or removed. When I send the email, the pictures are inserted correctly and the receiver gets a mail with pictures (also looks correct in Sent Items).
This issue only surfaces when composing an email on Outlook for Mac. I am using following code:
Office.context.mailbox.item.addFileAttachmentAsync(uri,
assetName,
{ },
function (asyncResult) {
if (asyncResult.status == "failed") {
console.log("Attach action failed with error: " + asyncResult.error.message);
deferred.reject();
}
else {
console.log("Attach action successfull");
deferred.resolve();
}
});
Have you attempted to do a saveAsync() after adding the file? I know a number of settings are not propagated until an email is sent or saved as a draft. Unfortunately I'm unable to set up a test to confirm what affect this will have but it may be worth a try:
Office.context.mailbox.item.saveAsync(
function callback(result) {
// Process the result
});
If you would like to use inline images as attachments, you will need to specify isInline as true as one of the parameters. This is part of Requirement Set 1.5 which may not be available on your version of Outlook for Mac. Below is a code snippet with an example.
Office.context.mailbox.item.addFileAttachmentAsync
(
"http://i.imgur.com/WJXklif.png",
"cute_bird.png",
{
isInline: true
},
function (asyncResult) {
Office.context.mailbox.item.body.setAsync(
"<p>Here's a cute bird!</p><img src='cid:cute_bird.png'>",
{
"coercionType": "html"
},
function (asyncResult) { }
);
}
);
to make my question short and simple:
How can I access the mediaFile generated by cordova-plugin-media-capture's function capture.captureVideo() and convert it with gifShot JS' createGIF()function into a GIF on an Android device?
I ran into the problem, that neither the fullPath (file:/URI), nor the localURL (cdvfile://) of the generated mediaFile are permitted for the use, if I directly give one of them as path for the video file for gifshot, I receive following message:
Cross-origin image load denied by Cross-Origin Resource Sharing policy.
I know that the file plugin successfully creates the videos (I can see them in the galery, so they are saved on the device permanently).
And I also know that gifShot works with mp4 videos as I already created a folder inside the project directory containing a video which it rendered correctly. I also know that sadly JavaScript normally is not permitted to gain access to files on a device/PC, but isn't there a workaround provided with Cordova?
Can someone briefly explain me, how I could access the saved file? Do I need the cordova plugins "cordova-plugin-file" and "cordova-plugin-file-transfer" and how do I use them?
My code:
Javascript:
import gifshot from 'gifshot';
Template.gifshotTest.rendered = function () {
var $$ = Dom7;
var myapp = new Framework7();
};
Template.gifshotTest.events({
'click .gifShotUpload': function () {
Meteor.call("console", "Button clicked");
// capture callback
var captureSuccess = function (mediaFiles) {
path = mediaFiles[0].localURL;
Meteor.call("console", mediaFiles[0]);
gifshot.createGIF({video: path}, function(obj) {
Meteor.call("console", "---> gifshot obj:");
Meteor.call("console", obj);
if (!obj.error) {
var image = obj.image;
$('.giffy').attr("src", image);
Meteor.call("console", image);
}
});
};
// capture error callback
var captureError = function (error) {
navigator.notification.alert('Error code: ' + error.code, null, 'Capture Error');
};
// start video capture
navigator.device.capture.captureVideo(captureSuccess, captureError, {limit: 1, duration: 5, quality: 1});
}
});
Console logs
I20160421-15:25:36.283(2)? Button clicked
I20160421-15:25:42.158(2)? null
I20160421-15:25:42.166(2)? { name: 'VID_20160421_152544.mp4',
I20160421-15:25:42.167(2)? localURL: 'cdvfile://localhost/sdcard/DCIM/Camera/VID_20160421_152544.mp4',
I20160421-15:25:42.167(2)? type: 'video/mp4',
I20160421-15:25:42.168(2)? lastModified: null,
I20160421-15:25:42.168(2)? lastModifiedDate: 1461245147000,
I20160421-15:25:42.169(2)? size: 461498,
I20160421-15:25:42.169(2)? start: 0,
I20160421-15:25:42.169(2)? end: 0,
I20160421-15:25:42.170(2)? fullPath: 'file:/storage/emulated/0/DCIM/Camera/VID_20160421_152544.mp4' }
I20160421-15:25:44.656(2) (android:http://localhost:12680/:0) Cross-origin image load denied by Cross-Origin Resource Sharing policy.
Included Cordova Plugins (Cordova Version 3.8.3):
cordova-plugin-file#4.1.1
cordova-plugin-file-transfer#1.5.1
cordova-plugin-media-capture#1.2.0
Thanks to everyone who helps me understanding the way Cordova and other libraries handle files on a device.
If the file is successfully stored in device, you can open the same use using cordova-fileopener-plugin. I would also suggest you to update your cordova version as the one you are using is too old