0

I am trying to run a WebApp which allows files sharing. After few google search, I found Web Share API like the standard to do so. According to the documentation it should works like this using plain JS

This is the code for html page

<p><button>Share MDN!</button></p>
<p class="result"></p>

The code to share all sort "textbased" metadata:

let shareData = {
  title: 'MDN',
  text: 'Learn web development on MDN!',
  url: 'https://developer.mozilla.org',
}

const resultPara = document.querySelector('.result');

if (!navigator.canShare) {
  resultPara.textContent = 'navigator.canShare() not supported.';
}
else if (navigator.canShare(shareData)) {
  resultPara.textContent = 'navigator.canShare() supported. We can use navigator.share() to send the data.';
} else {
  resultPara.textContent = 'Specified data cannot be shared.';
}

The code above works fine, the trouble happens when I try to share files.

According to the documentation it should works like this:

// filesArray is an array of files we want to share (audios, images, videos, pdf)
if (navigator.canShare && navigator.canShare({ files: filesArray })) {
  navigator.share({
    files: filesArray,
    title: 'Pictures',
    text: 'Our Pictures.',
  })
  .then(() => console.log('Share was successful.'))
  .catch((error) => console.log('Sharing failed', error));
} else {
  console.log(`Your system doesn't support sharing files.`);
}

I started my code from this example and I never success to share a file. My actual code using React and Typescript looks like this:

//some react code here


      const shareNow = async () => {
        let imageResponse = await window.fetch('https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png', {mode: "no-cors"});
        let imageBuffer = await imageResponse.arrayBuffer();
        let fileArray = [new File([imageBuffer], "File Name", {
          type: "image/png",
          lastModified: Date.now()
        })];


       if (navigator.canShare && navigator.canShare({ files: filesArray })) {
          navigator.share({
            files: filesArray
          }).then(() => {
            console.log('Thanks for sharing!');
          })
          .catch(console.error);
        }

        
      }

//some react code here too

At this point, my typescript compiler yell at me. Apparently, the navigator object has no method canShare()

The compiler yelling

I am new to typescript, but I don't understand how and why the navigator could have less attribute since TypeScript is JavaScript superset.

Anyone has an idea on how to solve that except running normal JS ?

Thank you for your time reading this, and I hope to thank you for your answers.

P.S: I also tried a react-component based solution, but all the component I found in open source which wraps Web Share API does not allow file sharing.

Edit

Hey, @DenverCoder9

There is the same use case but using vanilla JS, could anyone try it and tell me what I am doing wrong please ?

<html>

<head>
    <title>Sharing Image</title>
    <meta charset="UTF-8" />
</head>

<body>
    <div className="App">
        <img src="https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png"/>
        <button id="button">Share</button>
    </div>
</body>

<script>
    async function shareImage(title, imageUrl) {
        const image = await fetch(imageUrl, {mode: "no-cors"});
        const blob = await image.blob();
        const file = new File([blob], title, { type: 'image/png' });
        const filesArray = [file];

        const shareData = {
        files : filesArray

        }
        // add it to the shareData

        const navigator = window.navigator
        const canShare = navigator.canShare && navigator.canShare(shareData)  //navigator.canShare()navigator.share  //navigator.canShare()

        if(canShare){
        navigator.share(shareData)
        .then(() => console.log('Successful share'))
        .catch((error) => console.log('Error sharing', error));
        }
        else {
            console.log("cannot share this file in this context")
        }
    }

    document.getElementById('button').onclick = function() {
    shareImage("Title", "https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png")
    };
</script>

</html>

I am running this on safari for mac

1 Answers1

0

This is more of a TypeScript issue than a coding issue. Support for the Web Share API (Level 2) was added in this PR, so you can either update to a version of TypeScript that includes this, or alternatively teach your current TypeScript version the relevant types as follows:

type ShareData = {
    title? : string;
    text? : string;
    url? : string;
    files?: ReadonlyArray<File>;
};

interface Navigator
{
    share? : (data? : ShareData) => Promise<void>;
    canShare?: (data?: ShareData) => boolean;
}
DenverCoder9
  • 2,024
  • 11
  • 32
  • Thanks for your answer @DenverCoder9, I installed a version of typescript with all the types. But, now I have another issue using the share API. The function ` navigator.canShare({ files: filesArray })` alway returns false, and I don't know how to read the source code of this function to understand why. At coding time this function is abstract and at runtime trough the browser I cannot access the source code. Any Idea ? – Guy Stephane Manganneau Dec 12 '21 at 19:38
  • Could it be that you try to share unsupported file types? See the [list of currently supported types](https://developer.mozilla.org/en-US/docs/Web/API/Navigator/share#shareable_file_types) on MDN. – DenverCoder9 Dec 13 '21 at 10:54
  • I hoped it was just that but, I checked the documentation, and the type 'image/png' is an accepted one. Do you know which tool I can use to be able to see the code source of the 'canShare()' function, and debug it , The source code is not accessible in the safari/chrome debugger – Guy Stephane Manganneau Dec 13 '21 at 23:00
  • If you really want to dive into the browser code, this is the [deep link](https://github.com/chromium/chromium/blob/de8c857c883dc8278c29ee8609adf5d900eeb446/third_party/blink/renderer/modules/webshare/navigator_share.cc#L77). It would probably be easier to share a test case with your issue here, so the community can debug. It could be a size problem, too (too large image files). – DenverCoder9 Dec 15 '21 at 11:49
  • Thank you @DenverCoder9 I added a vanilla JS/html on the question – Guy Stephane Manganneau Dec 20 '21 at 10:29
  • The problem is CORS. While you can get the image via `fetch()`, you get a so-called opaque response, which can't be shared. Other than that, your code is fine. I have deployed a version of your code [on Glitch](https://cut-deep-ankle.glitch.me/) for you to test. Try moving your image to the same origin, use a CORS proxy server, or try adding the `Access-Control-Allow-Origin` header to your image server, then it should work, too. – DenverCoder9 Dec 21 '21 at 12:18