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

navigator.share (Web Share API) is not working inside a Webview #1262

Closed
anton-bot opened this issue Mar 19, 2020 · 19 comments
Closed

navigator.share (Web Share API) is not working inside a Webview #1262

anton-bot opened this issue Mar 19, 2020 · 19 comments

Comments

@anton-bot
Copy link

Bug description:

I have a <WebView> in my app built using Expo and React Native.

The webview opens a page that uses the Web Share API, i.e. navigator.share({ url: 'url' }).

However, navigator.share is not available inside the webview.

If the same page is opened within a normal browser, sharing works as expected.

To Reproduce:

Call navigator.share from inside a page opened in a webview and see that it's undefined.

Expected behavior:

navigator.share should be defined and working.

Environment:

  • OS: Android
  • OS version: 8
  • react-native version: "react-native": "https://github.com/expo/react-native/archive/sdk-35.0.0.tar.gz",
  • react-native-webview version:
@fhenri42
Copy link

Hello any update on this issue?

@riteshvsharma
Copy link

I am facing the same issue with Webview on Android. It works perfectly on iOS. Any updates?

@fodkastir
Copy link

navigator.share is not supported in Webview: https://developer.mozilla.org/en-US/docs/Web/API/Navigator/share

@Mohsin92
Copy link

Mohsin92 commented Jul 2, 2020

I am facing the same issue.
If in iOS working then why can't we can run in Android webview?

@alpkahveci
Copy link

omg why does not work in android webview? It is not normal. i am opening in mobile browser, it is working perfectly but in webview app not work! (they have completely same user agent !!)

@alpkahveci
Copy link

Guyz! I have a good news. You can do it with native and javascript. here is the solution. I hope it will work for you :)

@github-actions
Copy link

Hello 👋, this issue has been opened for more than 2 months with no activity on it. If the issue is still here, please keep in mind that we need community support and help to fix it! Just comment something like still searching for solutions and if you found one, please open a pull request! You have 7 days until this gets closed automatically

@vjbobeldijk
Copy link

It's still driving me crazy 30-10-2020

@simple-software-lab
Copy link

How do you re-open this issue? It is still a problem...

@ramisalem
Copy link

Any updates on this?

@r000bin97
Copy link

Does anyone have a solution?

@vjbobeldijk
Copy link

For my website on android chrome and iphone safari, I had the problem being stuck when opening my website from within the messenger webview. So I force open those browsers with some javascript code. Maybe you could open a new page with the navigator.share on it. But then you aren't in your own webview anymore. And I have a website, not an app. If you want that little piece of javascript, please tell.

@simioni
Copy link

simioni commented Sep 29, 2021

This is still a problem in late 2021. The navigator.share() method has been around since 2017, but it's still not supported in the Android WebView. This is not specific to React Native, so I don't know if there is any solution that can come from this project apart from instructions on how to do it directly from java / kotlin.

Luckily, it's easy enough to launch a share intent from native android code. All that is needed is an interface object to expose methods that can be called from javascript. @alpkahveci linked to some code that shows how to add such an interface in java.

Here's an example on how to do it using Kotlin:


  1. In your android project, just call addJavascriptInterface in your WebView to attach an interface to it.

MainActivity.kt

package com.your.app

class MainActivity : AppCompatActivity() {
  private lateinit var webViewComponent: WebView

  override fun onCreate(savedInstanceState: Bundle?) {
    setupWebview()
  }

  private fun setupWebview() {
    webview.settings.javaScriptEnabled = true
    // ... any other webview settings here

    val webAppInterface = WebAppInterface(this) // <- methods in this interface will become available to Javascript
    webview.addJavascriptInterface(webAppInterface, "Android") // <- methods will be exposed in global obj named Android
  }
}
  1. Then create the interface class that will expose any method you want to javascript. In this case we'll expose one that launches an activity for a simple share intent.

WebAppInterface.kt

package com.your.app

import androidx.core.content.ContextCompat.startActivity // <- helper to start an activity from any class

class WebAppInterface(private val mContext: Context) {
  @JavascriptInterface // <- this decorator is what exposes the method
  fun nativeShare(title: String, text: String, url: String) {
    val sendIntent: Intent = Intent().apply {
      action = Intent.ACTION_SEND
      putExtra(Intent.EXTRA_TITLE, title)
      putExtra(Intent.EXTRA_TEXT, "$text $url")
      type = "text/plain"
    }
    val shareIntent = Intent.createChooser(sendIntent, null)
    startActivity(mContext, shareIntent, null)
  }
}
  1. And then in Javascript.

Component.jsx

const Component = () => {
  const shareData = {
    title: 'Title to appear in the share sheet title bar',
    text: `Some text to be shared`,
    url: 'https://anyurl.com'
  }
  const handleShare = async () => {
    if ('Android' in window) {
      Android.nativeShare(shareData.title, shareData.text, shareData.url)
      return
    }
    try {
      await navigator.share(shareData)
      console.log('shared successfully')
    } catch (err) {
      console.log('Error: ' + err)
    }
  }
  return (
    <button onClick={handleShare}>Share</button>
  )
}

export default Component

@elise-ng
Copy link

elise-ng commented Oct 4, 2021

Solution by overriding navigator.share() to forward param to react native side for handling:

  1. Inject js before content loaded
// pass this in WebView injectedJavaScriptBeforeContentLoaded props
const injectedJavaScriptBeforeContentLoaded = `
if (navigator.share == null) {
  navigator.share = (param) => {
     window.ReactNativeWebView.postMessage('share:' + JSON.stringify(param));
  };
};
true;
`;
  1. Add onMessage callback to handle passed params, call react native's Share to invoke native share sheet
import { Share } from "react-native"

interface WebShareAPIParam {
  // ref https://developer.mozilla.org/en-US/docs/Web/API/Navigator/share
  url?: string;
  text?: string;
  title?: string;
  // files unhandled
}

// pass this in WebView onMessage props
const onMessage = useCallback(async (e: WebViewMessageEvent) => {
  const {data} = e.nativeEvent;
  if (data.startsWith('share:')) {
    try {
      const param: WebShareAPIParam = JSON.parse(data.slice('share:'.length));
      if (param.url == null && param.text == null) {
        return;
      }
      await Share.share(
        {
          title: param.title,
          message: [param.text, param.url].filter(Boolean).join(' '), // join text and url if both exists
          url: param.url,
        },
        {
          dialogTitle: param.title,
          subject: param.title,
        },
      );
    } catch (e: unknown) {
      console.error(e);
    }
  }
}, []);

@JKDos
Copy link

JKDos commented Feb 21, 2022

Still an issue in 2022. Did anyone find a solution not involving Java or Koplin?

@tungnguyen741
Copy link

My solution with deeplink
a with href href="intent:#Intent;action=your.example.namespace.CUSTOMACTION;package=your.example.namespace;component=your.example.namespace/.activity.YourActivity;S.extraValueName=WOW;end">

@denissb
Copy link

denissb commented Sep 13, 2022

@Simoni
How are you getting a reference to webview object in MainActivity?
This is the only part I can't quite seem to figure out.

@simioni
Copy link

simioni commented Sep 14, 2022

@denissb

@Simoni How are you getting a reference to webview object in MainActivity? This is the only part I can't quite seem to figure out.

It's the ID of the webview component in the activity XML. In Kotlin these UI bindings are exposed automatically, but it's the equivalent of findViewById.

If you created your Kotlin project from Android Studio this should just work. But if not, you can check this out:
https://stackoverflow.com/questions/46882421/cant-access-edittext-or-other-ui-components-with-kotlin

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

No branches or pull requests

16 participants