Is it possible to trigger share menu on smartphones (via HTML/JS)? - javascript

Is there an existing possibility to trigger the share functionality in local browsers on smartphones via HTML or JavaScript?
Of course there are many services which provide a share button. But when I e.g. want to share a website on facebook, I need to be logged in to facebook in the browser I am currently using.
Almost all browsers got an own share functionality build in, which triggers a system menu to choose which app you want to use to share:
This question is about: How to trigger this menu?
I know it is possible to trigger a phone call with a specified prefix in href attribute of links, like tel: or callto:. Maybe such a shortcut for this share menu is also existing? Or some javascript code? Or a totally different way how to do it?
Thanks in advance.

It is possible with a big catch. Currently only available in Chrome for Android, Samsung internet and on Safari (desktop and mobile). And support is coming to Edge and Chrome on desktop http://caniuse.com/#feat=web-share
if (navigator.share) {
navigator.share({
title: document.title,
text: "Hello World",
url: window.location.href
})
.then(() => console.log('Successful share'))
.catch(error => console.log('Error sharing:', error));
}
https://developers.google.com/web/updates/2016/10/navigator-share

I added this as all answers seems outdated by 2018-07-16.
It is possible, but only in a few browsers (MDN Reference), achieved througth the one method API in navigator:
navigator
.share({
title: document.title,
text: 'Hello World',
url: window.location.href
})
.then(() => console.log('Successful share! 🎉'))
.catch(err => console.error(err));
Google's reference: https://developers.google.com/web/updates/2016/10/navigator-share
Also, there was a thing called Web Intends which is a dead project, you should go with navigator.share instead.

It's now possible with the Web Share API!
However, it isn't widely supported as of yet. Currently, it's only available in Safari (mobile and desktop), and Chrome for Android. See Can I Use for details.
According to Introducing the Web Share API on Google Developers, there are several things to keep in mind:
your page needs to be served over HTTPS
you can only call navigator.share(…) in response to a user action, such as a click (i.e., you can't call it on page load)
you should feature-detect it in case it's not available on your users' platform (e.g., via navigator.share !== undefined)
The Google Developers article also notes that URLs shared with the Share API need not be on your own domain—you can share any URL.
Putting that all together, you could use something like this which uses the Share API if it's available, and falls back to sending an email if it's not*:
function createShareButton() {
const btn = document.createElement("button");
const title = document.title;
const text = "Check this out!";
const url = window.location.href;
btn.innerText = "share" in navigator ? "Share" : "Share via e-mail";
btn.onclick = () => {
if (navigator.share !== undefined) {
navigator
.share({
title,
text,
url
})
.then(() => console.log("Shared!"))
.catch(err => console.error(err));
} else {
window.location = `mailto:?subject=${title}&body=${text}%0A${url}`;
}
};
return btn;
}
document.title = "Demo";
document.body.appendChild(createShareButton());
*: Please do consider using a more appropriate fallback, (e.g., social sharing) depending on your use case.

Answered Apr 10 2013
To my knowledge, there is no such implementation in current browsers on mobile OS's. Since the question interested me - a google search revealed there is work being done in this direction:
https://dvcs.w3.org/hg/web-intents/raw-file/tip/spec/Overview.html
http://webintents.org/
Sorry - I do not know a workaround.

It is possible and I wrote a function to have pretty content to share and observe the asynchronous side effects:
const shareContact = async (title, content) => {
const text = `${title}
${content}`;
try {
await navigator.share({
text,
});
} catch (e) {
console.log(e);
}
};

You could use the WebView.addJavascriptInterface() method for android.
First you will need to write a class which fires the intent to open the share menu(take a look here) and then implement that class using the addJavascriptInterface() call. After that all you need to do is call the method from your Javascript.

Related

JavaScript dialogs alert(), confirm() and prompt() in cross origin iframe does not work any longer

Apps script web app works in <iframe>. It seems Chrome is no longer supporting alert(), confirm(), Promote these functions on the web app.
Any workaround to this?
Chrome Version 92.0.4515.107 (Official Build) (64-bit) -- does not work
Edge Version 91.0.864.71 (Official build) (64-bit) -- works
Tried replacing alert() with window.alert(), but still does not work.
exec:1 A different origin subframe tried to create a JavaScript dialog. This is no longer allowed and was blocked. See https://www.chromestatus.com/feature/5148698084376576 for more details.
This is absurd and subjective decision of Google to remove alert(), confirm(), and prompt() for cross origin iframes. And they called it "feature". And justification is very poor - see "motivation" bellow. A very weak reason for removing such an important feature! Community and developers should protest!
Problem
https://www.chromestatus.com/feature/5148698084376576
Feature: Remove alert(), confirm(), and prompt for cross origin iframes
Chrome allows iframes to trigger Javascript dialogs, it shows “ says ...” when the iframe is the same origin as the top frame, and “An embedded page on this page says...” when the iframe is cross-origin. The current UX is confusing, and has previously led to spoofs where sites pretend the message comes from Chrome or a different website. Removing support for cross origin iframes’ ability to trigger the UI will prevent this kind of spoofing, and unblock further UI simplifications.
Motivation
The current UI for JS dialogs (in general, not just for the cross-origin subframe case) is confusing, because the message looks like the browser’s own UI. This has led to spoofs (particularly with window.prompt) where sites pretend that a particular message is coming from Chrome (e.g. 1,2,3). Chrome mitigates these spoofs by prefacing the message with “ says...”. However, when these alerts are coming from a cross-origin iframe, the UI is even more confusing because Chrome tries to explain the dialog is not coming from the browser itself or the top level page. Given the low usage of cross-origin iframe JS dialogs, the fact that when JS dialogs are used they are generally not required for the site’s primary functionality, and the difficulty in explaining reliably where the dialog is coming from, we propose removing JS dialogs for cross-origin iframes. This will also unblock our ability to further simplify the dialog by removing the hostname indication and making the dialog more obviously a part of the page (and not the browser) by moving it to the center of the content area. These changes are blocked on removing cross-origin support for JS dialogs, since otherwise these subframes could pretend their dialog is coming from the parent page.
Solution
Send message via Window.postMessage() from iframe to parent and show dialog via parent page. It is very elegant hack and shame on Google because before Chrome version 92 client saw alert dialog e.g. An embedded page iframe.com" says: ... (which was correct - client see real domain which invoked alert) but now with postMessage solution client will see a lie e.g. The page example.com" says: ... but alert was not invoked by example.com. Stupid google decision caused them to achieve the opposite effect - client will be much more confused now. Google's decision was hasty and they didn't think about the consequences. In case of prompt() and confirm() it is a little bit tricky via Window.postMessage() because we need to send result from top back to iframe.
What Google will do next? Disable Window.postMessage()? DĂ©jĂ  vu. We are back in Internet Explorer era... developers waste time by doing stupid hacks.
TL;DR: Demo
https://domain-a.netlify.app/parent.html
Code
With code bellow you can use overridden native alert(), confirm() and prompt() in cross origin iframe with minimum code change. There is no change for alert() usage. I case of confirm() and prompt() just add "await" keyword before it or feel free to use callback way in case you can not switch easily your sync functions to async functions. See all usage examples in iframe.html bellow.
Everything bad comes with something good - now I gained with this solution an advantage that iframe domain is not revealed (domain from address bar is now used in dialogs).
https://example-a.com/parent.html
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Parent (domain A)</title>
<script type="text/javascript" src="dialogs.js"></script>
</head>
<body>
<h1>Parent (domain A)</h1>
<iframe src="https://example-b.com/iframe.html">
</body>
</html>
https://example-b.com/iframe.html
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Iframe (domain B)</title>
<script type="text/javascript" src="dialogs.js"></script>
</head>
<body>
<h1>Iframe (domain B)</h1>
<script type="text/javascript">
alert('alert() forwarded from iframe.html');
confirm('confirm() forwarded from iframe.html via callback', (result) => {
console.log('confirm() result via callback: ', result);
});
prompt('prompt() forwarded from iframe.html via callback', null, (result) => {
console.log('prompt() result via callback: ', result);
});
(async () => {
var result1 = await confirm('confirm() forwarded from iframe.html via promise');
console.log('confirm() result via promise: ', result1);
var result2 = await prompt('prompt() forwarded from iframe.html via promise');
console.log('prompt() result via promise: ', result2);
})();
</script>
</body>
</html>
dialogs.js
(function() {
var id = 1,
store = {},
isIframe = (window === window.parent || window.opener) ? false : true;
// Send message
var sendMessage = function(windowToSend, data) {
windowToSend.postMessage(JSON.stringify(data), '*');
};
// Helper for overridden confirm() and prompt()
var processInteractiveDialog = function(data, callback) {
sendMessage(parent, data);
if (callback)
store[data.id] = callback;
else
return new Promise(resolve => { store[data.id] = resolve; })
};
// Override native dialog functions
if (isIframe) {
// alert()
window.alert = function(message) {
var data = { event : 'dialog', type : 'alert', message : message };
sendMessage(parent, data);
};
// confirm()
window.confirm = function(message, callback) {
var data = { event : 'dialog', type : 'confirm', id : id++, message : message };
return processInteractiveDialog(data, callback);
};
// prompt()
window.prompt = function(message, value, callback) {
var data = { event : 'dialog', type : 'prompt', id : id++, message : message, value : value || '' };
return processInteractiveDialog(data, callback);
};
}
// Listen to messages
window.addEventListener('message', function(event) {
try {
var data = JSON.parse(event.data);
}
catch (error) {
return;
}
if (!data || typeof data != 'object')
return;
if (data.event != 'dialog' || !data.type)
return;
// Initial message from iframe to parent
if (!isIframe) {
// alert()
if (data.type == 'alert')
alert(data.message)
// confirm()
else if (data.type == 'confirm') {
var data = { event : 'dialog', type : 'confirm', id : data.id, result : confirm(data.message) };
sendMessage(event.source, data);
}
// prompt()
else if (data.type == 'prompt') {
var data = { event : 'dialog', type : 'prompt', id : data.id, result : prompt(data.message, data.value) };
sendMessage(event.source, data);
}
}
// Response message from parent to iframe
else {
// confirm()
if (data.type == 'confirm') {
store[data.id](data.result);
delete store[data.id];
}
// prompt()
else if (data.type == 'prompt') {
store[data.id](data.result);
delete store[data.id];
}
}
}, false);
})();
File a feature request:
Consider filing a feature request using this Issue Tracker template.
I'd either request that an exception is made for Apps Script web apps, or that built-in methods for alert and confirm are added, similar to the existing alert and prompt dialogs, which currently work on Google editors.
Bug filed:
By the way, this behavior has been reported in Issue Tracker (as a bug):
Javascript in html files doesn't work
I'd consider starring it in order to keep track of it.
Workaround:
In the meanwhile, as others said, consider downgrading or changing the browser, or executing it with the following command line flag:
--disable-features="SuppressDifferentOriginSubframeJSDialogs"
Related question:
Chrome SuppressDifferentOriginSubframeJSDialogs setting override using JS?
So far, the only 'solution' for this is to add the following to your Chrome/Edge browser shortcut:
--disable-features="SuppressDifferentOriginSubframeJSDialogs"
Or downgrade your browser. Obviously neither of these are ideal. Google trying really hard to save us from ourselves here.

Web Share API permission missing

I'm trying to implement the Web Share Api functionality on my test web app but it doesn't seem I'm able to do it. This is the code:
const newVariable: any = navigator;
{newVariable && newVariable.share && <IconButton aria-label="Share" onClick={async (e) => {
try {
const id = await shareRepository.shareTrip(this.props.todolist)
const url = "https://something.com/share/" + id
await newVariable.share({
title: 'Check my todolist for ' + this.props.todolist.trip.departure + ' - ' + this.props.todolist.trip.arrival,
text: 'Check my todolist for ' + this.props.todolist.trip.departure + ' - ' + this.props.todolist.trip.arrival,
url: url,
})
} catch (error) {
alert(error)
}
}}>
<ShareIcon />
</IconButton>}
Every time I try on both Firefox and Safari for iOS, I'm getting an error saying:
NotAllowedError: the request is not allowed by the user agent or the platform in the current context, possibly because the user denied permission.
If on those browser I try to share something from google.com I get the native dialog to choose with which app to share.
I cannot understand why. On this page there is no discussion about permission: https://developers.google.com/web/updates/2016/09/navigator-share
UPDATE:
on Chrome for android works just fine, on Firefox for Android doesn't work. On Chrome, Firefox and Safari (which I believe they use safari engine all three) is only working if I pass "" which means the page itself, or "https://something.com/share/", it breaks If I pass "https://something.com/share/"+id :/
For other future users where the current answer is too specific to that code. The root issue is that the share() method must be called from a user gesture.
If the method call was not triggered by user activation, return a promise rejected with with a "NotAllowedError" DOMException.
From the Web Share API.
A user activation is any of the following:
change
click
contextmenu
dblclick
mouseup
pointerup
reset
submit
touchend
I understood what was the issue, which is absolutely annoying.
So:
const id = await shareRepository.shareTrip(this.props.todolist)
This call is the one that is causing problems. If I comment it, on iOS there is no issue.
If I keep it I have no problem at all on Android but iOS will complain.
So I need to rethink the flow of the application to pass the id from outside the 'onClick' event.

Facebook SDK change display type in the FB.login()

I'm working on the Facebook Login integration into my website and I've done everything which was necessary to achieve this and described in the Facebook documentation
So I'm using FB.login() method
export function facebookLogin() {
return new Promise((res: any, rej: any) => {
// TODO: maybe it might be moved to some dedicated API file? But we don't want to use it anywhere else
FB.login((response: FacebookLoginCallbackResponse) => {
if (response.authResponse) {
res(response.authResponse);
} else {
rej();
}
}, {scope: "public_profile, email"});
});
}
It works fine but when the popup is opened (and it's really big. I would like to make it smaller) the warning shows at the bottom of window.
You are using a display type of 'page' in a small browser window or popup. For a better user experience, show this dialog with our JavaScript SDK without specifying an explicit display type. The SDK will choose the best display type for each environment
The question is: How to change it? There is no option TYPE in the Login Dialog parameters. I didn't found anything about this possibility in the Login Dialog documentation.
Can someone give me some tip, please?

React-Native Link app to Facebook Messenger

I know I can deep link maps for example, I used it and it works fine. But how about FB Messenger? I have a button, that when user clicks I want it to open Messenger with a conversation with someone. How can I do it? I tried directly linking but it doesn't work.
openMessenger() {
Linking.canOpenURL('https://www.messenger.com/t/name').then(supported => {
if (supported) {
Linking.openURL('https://www.messenger.com/t/name');
} else {
console.log('erro');
}
}).catch(err => console.error('An error occurred', err));
}
also tried fb-messenger://user-thread/{user-id} and still didn't work.
btw, is there any way to ask the user which app he wants to open with? In the case of the maps, when I click the button it opens on Apple Maps on iOS, but I want it to ask which app to open instead, as I don't use Apple Maps for example.
Linking.canOpenURL('fb-messenger://').then(supported => {
if (!supported) {
console.log('Can\'t handle url: ' + url);
} else {
Linking.openURL("fb-messenger://user-thread/" + "facebook id");
}
}).catch(err => console.log(err)));
iOS
As of iOS 9, your app needs to provide the LSApplicationQueriesSchemes
key inside Info.plist or canOpenURL will always return false.
Set LSApplicationQueriesSchemes => Restart server
<key>LSApplicationQueriesSchemes</key>
<array>
<string>fbapi</string>
<string>fb-messenger-share-api</string>
<string>fbauth2</string>
<string>fbshareextension</string>
<string>fb-messenger</string>
</array>
Android
To support deep linking on Android, refer
http://developer.android.com/training/app-indexing/deep-linking.html#handling-intents
For those looking for an answer, this library worked for me:
https://github.com/fiber-god/react-native-app-link
In case you are still wondering this is a straightforward way just to messenger to the existing react native application without any packages
Linking.openURL(http://m.me/<PAGE_NAME>)
Official Documentation

How to make desktop notifications stay?

I have this notification, but it only shows for ~5 seconds. I would like it to stay for longer/or make it stay until I click on it.
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
if ((String(tab.title).search("Sniped:"))==0){
var notification = webkitNotifications.createNotification(
'face.png',
'Sniper',
tab.title
);
notification.show();
}
});
Suggestions on how to do this please?
I don't think it's possible using the webkitNotifications API.
You could use the Rich Notification API from chrome.experimental.notification. They're not a lot of information on this API yet, but Google released a short video containing a couple of examples, which can be seen here: http://www.youtube.com/watch?v=g8fJWB2-pYk.
However note that if you decide to use the APIs from chrome.experimental then you cannot release your app on the Chrome Web Store. More info on the experimental APIs can be found at http://developer.chrome.com/extensions/experimental.html
also you can do this before call the function "show()":
notification.ondisplay = function(event) {
setTimeout(function() {
event.currentTarget.cancel();
}, 10000);
};
I think you know how to work with it.

Categories

Resources