Not allowed to launch cutom protocol because a user gesture is required - javascript

I need to run my custom protocol twice but it doesn't work the second time, I got this error ( Not allowed to launch 'cutomProtocol' because user gesture is required. ) I tried to find a solution but I did not find any!
Same problem with chrome, firefox and edge.
I need to see this popup twice
window.location.href = 'my-protocol://${base64}';
and
customProtocolVerify(
`my-protocol://${base64}`,
() => {
// successCb: Callback function which gets called when custom protocol is found.
console.log('My protocol found and opened the file successfully..');
},
() => {
// failCb: Callback function which gets called when custom protocol not found.
console.log('My protocol not found.');
}
);
I tried with these two and didn't work
Clarification
I have a custom protocol.
My scenario:
check if it's installed successfully (I'm using customProtocolVerify method) and that method makes the launch if the protocol is found
run some APIs
launch the protocol again
My problem:
Step 3 doesn't work, I have the error on the console that says " Not allowed to launch... " and of course I can't see my popup to open my protocol.
I'm asking for help to make step 3 work

The only way to bypass this "bug" is to ask the user twice (or in a loop) by showing a OK alert or some sort of user confirm box.
My solution:
OpenLinkInExternalApp(Link);
alerty.alert('', { title: '', okLabel: 'Open Link' }, function () {
OpenLinkInExternalApp(Link);
});
The above code will open the external app, then a OK alert will pop up, after clicking OK, I call the same code again. Do this in a loop if needed.
TIP:
We guide our users to use split screen at this stage. This is where users can dock your web-app on the left and the external app on the right as an example.
Alert Box:
We user Alerty.js https://github.com/undead25/alerty#readme

Related

Chrome, allow autoconnect for HID device

So I'm trying to read out a USB-scale thats connected to my pc. I use chrome's experimental HID api.
I use Tampermonekey as userscript injector to extend a website's functionality.
The script I inject looks like this:
navigator.hid.requestDevice({ filters: [{ vendorId: 0x0922, productId: 0x8003}] }).then((devices) => {
if (devices.length == 0) return;
devices[0].open().then(() => {
if(disconnected) {
disconnected = false
}
console.log("Opened device: " + devices[0].productName);
devices[0].addEventListener("inputreport", handleInputReport);
devices[0].sendReport(outputReportId, outputReport).then(() => {
console.log("Sent output report " + outputReportId);
});
});
});
When I run it just like this(inline) I get the message in chrome:
DOMException: Failed to execute 'requestDevice' on 'HID': Must be handling a user gesture to show a permission request.
Basically, the code needs to be inside an event listener and the listener needs to be triggered by user input to run.
Al fine and dandy, except that this has to be initialized hundreds of times a day. I tried running this code in edge and here it just works without user input.
Is there a way I can disable this security feature(completely or only for the site im using it on) in chrome? I know edge is based on chromium so I expect it to be possible, but am unable to find how/where
You can use HID.getDevices() to retrieve an HID device that the user has already granted access to.
My suggestion would be to check for the device you want with getDevices first. If you can't find the device, then make something the user can interact with that will allow you to use requestDevice to connect to the device.

VS2015 Cordova Sms Plugin Sms.Send doesn't work in Index.JS (ondeviceReady)

I'm new to Cordova, any help would be appreciated.
I created a new Cordova Project in VS2015 and added the Cordova SMS plugin to my project (https://www.npmjs.com/package/cordova-sms-plugin).
I added this code to /www/scripts/index.js function onDeviceReady (as per documentiation for plugin):
function onDeviceReady() {
// Handle the Cordova pause and resume events
document.addEventListener( 'pause', onPause.bind( this ), false );
document.addEventListener( 'resume', onResume.bind( this ), false );
var numberString = "aoeuaeu";
var bypassAppChooser = true;
//CONFIGURATION
var options = {
replaceLineBreaks: false,
android: {
intent: 'INTENT' // send SMS with the native android SMS messaging
}
};
var successSMS = function () { alert('Message sent successfully'); };
var errorSMS = function (e) { alert('Message Failed:' + e); };
sms.send("0811231234", "Testing123", options, successSMS, errorSMS);
I debug the project using Debug, Android, Ripple - Nexus (Galaxy) selected options. When I place a breakpoint on the sms.send line of code and I add a watch for 'sms.send', I can see the object exists.
When I single step, this line in sms.js seems to be the last line that executes:
// fire
exec(
success,
failure,
'Sms',
'send', [phone, message, androidIntent, replaceLineBreaks]
);
I then get the following error message in Ripple:
'Sms.send We seem to be missing some stuff :( What is kinda cool though you can fill in the textarea to pass a json object to the callback you want to execute).'
I can see that all of the objects in that line is defined (success, failure, phone, message, androidIntent, replaceLineBreaks). When I 'step into' this line, it continues to execute code in ripple.js, but it becomes hard to follow for a person, since there are no line breaks in this file.
What am I doing wrong? I've read through all the documentation I can find & searched stackoverflow questions and can't seem to find any solutions to the problem.
I've uploaded this entire project (zipped), which can be downloaded at:
https://drive.google.com/file/d/0BwWgTMh-JLbfNHV0MlE5Yk5IZ3M/view?usp=sharing
Thanks in advance
Thank you Cordova team at Microsoft for helping me with an answer:
"Ripple has the ability to emulate some but not all plugins. SMS is not one of the plugins that it can fully emulate. However, in the message that pops up, you do have the ability to hit the Success or Fail buttons which will report back to the app that it was successful or not in sending the SMS. While that doesn’t actually send a message, it does let you test your app to see how it behaves for different results.
I tried the bit of sample code you included in the first email. In Ripple, I was able to change the alert by hitting the different buttons.
Trying other deployment methods, in both the VS Android Emulator and the Google Emulator they showed failure alert messages that they don’t support SMS messages. I then launched it on an Android phone device and it said it was successful.
So I believe your options are mainly using Ripple to fake sending of messages or using a device for testing."

Why doesn't callback get called when the app is in background?

I'm developing a titanium app that needs to display a Banner Message under iOS when a push notification comes in. Therefore I used the following code to register on incoming push notifications:
var callbacks = {
types: [
Titanium.Network.NOTIFICATION_TYPE_BADGE,
Titanium.Network.NOTIFICATION_TYPE_SOUND,
Titanium.Network.NOTIFICATION_TYPE_ALERT
],
success:function(e){
console.log("success");
},
error:function(e){
console.log("error");
},
callback: function(e){
console.log("new push notification")
//code for displaying banner message would go here!
}
};
if(Ti.App.iOS.registerUserNotificationSettings){ //iOS 8 +
function onUserNotificationSettings(){
delete callbacks.types;
Ti.Network.registerForPushNotifications(callbacks);
Ti.App.iOS.removeEventListener("usernotificationsettings",onUserNotificationSettings);
}
Ti.App.iOS.addEventListener("usernotificationsettings",onUserNotificationSettings)
Ti.App.iOS.registerUserNotificationSettings(callbacks)
}else{ //up to iOS 7
Ti.Network.registerForPushNotifications(callbacks)
}
But the callback function does not get called when the app is in background. So, I also can't display the banner message there, since the code won't get executed.
What could be the reason why the callback does not get called when the app is in background? When it is in foreground, it works perfectly. Is it normal? If yes, where else would I put my code to display the banner message?
I'm using SDK version 3.4.0 on an iPhone 5 with iOS 8.1.1
Please note that sending the banner text through the apn-payload is not the solution. There are other usecases. For example, when the server needs to tell the client that there is new content to sync, where the user does not even need to get notified for. The client should just download the new content in background just when the notification arrives.
You need to register for the remote-notification background mode. This will wake up your app and give you execution time when you send the notifications.
For the record this is in the Appcelerator docs here
I've found out how to do it!
The callback will get called when the app is in background. All I had to do for it was to add the following to my tiapp.xml in ti:app/ios/plist/dict:
<key>UIBackgroundModes</key>
<array>
<string>remote-notification</string>
</array>
After that, everything works fine!

Checking if user has a certain extension installed

I just found out that the Screen Capture by Google extension makes my website's window.onresize event not fire.
I want to perform a javascript check to see if the user has ScreenCapture installed and if so, warn the user of the problem.
A year ago I think I heard of some javascript code that could do this, maybe using some google API, but I don't remember.
Any insight on this? I haven't developed any extensions so I don't really know how they work.
[EDIT]
So I have been asked to show some code. As seen in my previous question ( window.onresize not firing in Chrome but firing in Chrome Incognito ), the problem occurs on any window.onresize event function, so I don't think my code really matters.
Also, there is quite a lot of my code, I don't know how much of it to paste or if it would be helpful.
var debounce = function (func, threshold, execAsap)
{
var timeout;
return function debounced () {//alert("1.1 Y U NO WORK?");
var obj = this, args = arguments;
function delayed () {
if (!execAsap)
func.apply(obj, args);
timeout = null;
}
if (timeout)
clearTimeout(timeout);
else if (execAsap)
func.apply(obj, args);
timeout = setTimeout(delayed, threshold || 100);
};
};
window.onresize = debounce(function (e) { //alert("1.2 Y U NO WORK?");
flag = true;
var point = window.center({width:1,height:1});
doCenter(point);
// does something here, but only once after mouse cursor stops
}, 100, false);
I would like to stress that the problem is not due to the debounce. window.onresize = t; function t (e) { alert("wtf?");} won't work either.
[EDIT2]
Here's the result:
var screenCapture = null;
var screenCaptureImg = document.createElement("img");
screenCaptureImg.setAttribute("src", "chrome-extension://cpngackimfmofbokmjmljamhdncknpmg/images/arrow.png");
/*
* Add event listeners for both "load"- and "error"-event
* Set the variable showing the existence of the extension by
* setting it to "true" or "false" according to the fired event
*/
screenCaptureImg.addEventListener("load", doLoad, false);
function doLoad(e){
screenCapture = true; //removeImgTag(e);
alert("I've so cleverly detected that your Chrome has the ScreenCapture extension enabled. \n\nThis extension interferes with my website's DOM and long story short, it won't be able to scale properly.\n\nSo please disable it. \nConsider this extension: \"Disable All Extensions Plus\", it's a handy selective disabler.");
}
screenCaptureImg.addEventListener("error", function(e){
screenCapture = false; //removeImgTag(e);
}, false);
/*
function removeImgTag(e) {
e.currentTarget.parentNode.removeChild(e.currentTarget);
}
*/
Note that I couldn't get removeImgTag to work, because (at least in chrome), I don't seem to have access to the document object in order to create or remove elements from my page, from within these event functions. This is also why I'm displaying an alert instead of elegantly writing up a document.getElementById("something").innerHTML=...
To detect if an extension is installed in Chrome, you can check for a known resource included in the extension such as an image. Resources for the extension are referenced using the following URL pattern:
chrome-extension://<extensionID>/<pathToFile>
The basic detection technique involves creating a hidden image tag and attaching load and error events to it to see if the image loads (as described here for Firefox):
extensionImg.setAttribute("src", "chrome-extension://<INSERT EXTENSION ID HERE>/images/someImage.png"); // See below for discussion of how to find this
/*
* Add event listeners for both "load"- and "error"-event
* Set the variable showing the existence of the extension by
* setting it to "true" or "false" according to the fired event
*/
extensionImg.addEventListener("load", function(e) {
extensionExists = true;
removeImgTag(e);
}, false);
extensionImg.addEventListener("error", function(e) {
extensionExists = false;
removeImgTag(e);
}, false);
function removeImgTag(e) {
e.currentTarget.parentNode.removeChild(e.currentTarget);
}
Check the installation directory of the extension in the Chrome configuration to find a likely target for detection. On my Linux workstation extensions are located in:
~/.config/chromium/Default/Extensions
You can see that I have 3 extensions installed right now:
~/.config/chromium/Default/Extensions$ ls
cpecbmjeidppdiampimghndkikcmoadk nmpeeekfhbmikbdhlpjbfmnpgcbeggic
cpngackimfmofbokmjmljamhdncknpmg
The odd looking names are the unique IDs given to the extension when it is uploaded to the Chrome webstore. You can obtain the ID either from the webstore or by going to the Extensions tab (wrench -> Extensions) and hovering over the link to the extension in question, or "Screen Capture (by Google)" in this case (note the asterisked extension ID):
https://chrome.google.com/webstore/detail/**cpngackimfmofbokmjmljamhdncknpmg**
In the extension directory there will be one or more versions; you can ignore this. Within the version directory is the actual content of the extension:
~/.config/chromium/Default/Extensions/cpngackimfmofbokmjmljamhdncknpmg/5.0.3_0$ ls
account.js images page.js sina_microblog.js
ajax.js isLoad.js picasa.js site.js
background.html _locales plugin style.css
editor.js manifest.json popup.html ui.js
facebook.js notification.html sha1.js upload_ui.js
hotkey_storage.js oauth.js shortcut.js
hub.html options.html showimage.css
i18n_styles page_context.js showimage.html
In the case of the Screen Capture extension there are a number of images to use:
~/.config/chromium/Default/Extensions/cpngackimfmofbokmjmljamhdncknpmg/5.0.3_0/images$ ls
arrow.png icon_128.png icon_save.png print.png
copy.png icon_16.png line.png region.png
cross.png icon_19.png loading.gif screen.png
custom.png icon_32.png loading_icon.gif sina_icon.png
delete_account_icon.png icon_48.png mark.png toolbar_bg.png
down_arrow.png icon_close.png picasa_icon.png upload.png
facebook_icon.png icon_copy.png popup_bg.jpg whole.png
These can be referenced under this URL:
chrome-extension://cpngackimfmofbokmjmljamhdncknpmg/images/arrow.png
This technique obviously depends on the stability of the content of the extension. I recommend using an image that looks likely to remain through all versions.
As mentioned above, the same technique can be used to detect Firefox extensions. In this case the content URL looks like this:
chrome://<EXTENSION NAME>/content/<PATH TO RESOURCE>
On my Linux workstation Firefox extensions are located in:
~/.mozilla/firefox/<USER PROFILE ID>/extensions
Where <USER PROFILE ID> looks something like this: "h4aqaewq.default"
You can see that I have 2 extensions installed right now, one of which is a directory installation and the other of which is a XPI (pronounced "zippy") file:
~/.mozilla/firefox/h4aqaewq.default/extensions$ ls
{3e9a3920-1b27-11da-8cd6-0800200c9a66} staged
firebug#software.joehewitt.com.xpi
The "staged" directory is where Firefox keeps extensions that will be updated (I think). The GUID directory with the brackets is a directory-based extension installation, and the .xpi file is Firebug.
Note: XPI is going away (see the link above). It's basically a zip file that can be opened and inspected by anything that understands zip. I used Emacs.
Finding the extension ID in Firefox is a bit more involved. Go to "Tools -> Add-ons", click the Extensions tab, click the "More" link next to the extension description, then click the "reviews" link to go to the Firefox extension site and get the ID from the URL (note the asterisked extension ID):
https://addons.mozilla.org/en-US/firefox/addon/**firebug**/reviews/?src=api
There's probably an easier way to do this; suggestions welcome.
TODO: how to find a likely image in a Firefox extension.
As an extra note, in Chrome you can only communicate with an extension via the shared DOM of the page: Host page communication

How to detect Chrome extension uninstall

I am trying to detect whether my extension was uninstalled.
I can't use chrome.management.onUninstalled because it will be fired on other extension.
As of Chrome 41, you can now open a URL when the extension is uninstalled. That could contain an exit survey or track the uninstall event as some sort of analytics.
Google Chrome, unlike Firefox, doesn’t allow to detect when the user uninstalls the extension, which is quite useful to understand user behaviour.
There is a feature request on crbug.com with a discussion of this feature but it has not been implemented yet.
You can call chrome.runtime.setUninstallURL("www.example.com/survey") and redirect user to a url. Unfortunately, as soon as the extension is removed, the background script is removed too, and you can't do anything like log event or send hit to google analytics.
What I did is to set the redirect url to my server endpoint, and do some tasks like logging event to my own db, or sending hit to google analytics (ga hit builder). Then call res.status(301).redirect("www.example.com/survey") to some survey url. Finally I can send the uninstall event to google analysis.
If you're on Manifest V3, you can add it on your onInstalled Listener. If you want to capture uninstall for existing users as well, you need to add it to 'update' as well.
Place this code in your background page:
chrome.runtime.onInstalled.addListener(function (details) {
if (details.reason == 'install') {
... can add things like sending a user to a tutorial page on your website
chrome.runtime.setUninstallURL('https://www.yourwebsite.com/uninstall');
} else if (details.reason == 'update') {
... can add things like sending user to a update page on your website
chrome.runtime.setUninstallURL('https://www.yourwebsite.com/uninstall');
}
});
Find more information here: https://developer.chrome.com/docs/extensions/reference/runtime/#method-setUninstallURL
For mv3: An easy way would be to have
// Redirect users to a form when the extension is uninstalled.
const uninstallListener = (details) => {
if (details.reason === chrome.runtime.OnInstalledReason.INSTALL) {
chrome.runtime.setUninstallURL('https://forms.gle/...');
}
if (details.reason === chrome.runtime.OnInstalledReason.UPDATE) {
// TODO: show changelog
}
};
chrome.runtime.onInstalled.addListener(uninstallListener);
Place it in your background.
Content Script can Detect an Uninstall
Simply check the value of chrome.runtime, which becomes undefined when an extension is uninstalled.
A good trigger to check this is port disconnect:
// content_script.js
const port = chrome.runtime.connect();
port.onDisconnect.addListener(onPortDisconnect);
function onPortDisconnect() {
// After the extension is disabled/uninstalled, `chrome.runtime` may take
// a few milliseconds to get cleared, so use a delay before checking.
setTimeout(() => {
if (!chrome.runtime?.id) {
console.log('Extension disabled!');
}
}, 1000);
};

Categories

Resources