I have a packaged chrome app having multiple windows. For example if I click a button in first window then a second window opened. Now how to send messages or commands to each other.
I have read a lot about it but did not figure out as i am very much new to this.
Any sample code will be very helpful.
There is a existing question How to communicate between multiple windows of the same chrome app?, but did not understand how to do it.
Thanks in advance!!!
You can use the postmessage method of a window, in order to send information to another window. By following this approach, you can execute a method from a window (A) on a different window (B). You'll need to create an event on window B that will inform A that the method ran correctly.
The code would be something like:
Sender:
//create popup window
var domain = 'http://scriptandstyle.com';
var myPopup = window.open(domain + '/windowPostMessageListener.html','myWindow');
//periodical message sender
setInterval(function(){
var message = 'Hello! The time is: ' + (new Date().getTime());
console.log('blog.local: sending message: ' + message);
myPopup.postMessage(message,domain); //send the message and target URI
},6000);
//listen to holla back
window.addEventListener('message',function(event) {
if(event.origin !== 'http://scriptandstyle.com') return;
console.log('received response: ',event.data);
},false);
Destination:
//respond to events
window.addEventListener('message',function(event) {
if(event.origin !== 'http://davidwalsh.name') return;
console.log('message received: ' + event.data,event);
event.source.postMessage('holla back youngin!',event.origin);
},false);
You can also find an in-dept explanation here: http://davidwalsh.name/window-postmessage
In the case of a Chrome app, the part about the domain is not required.
You need something as:
targetWindow = chrome.app.window.get("window-id").contentWindow;
targetWindow.postMessage(message, "*");
to send a message, while to receive:
window.addEventListener('message', function(event) {
var windowId = chrome.app.window.current().id;
console.log(windowId + ': received a message: ' + event.data, event);
var message = 'hello back!';
console.log(windowId + ': sending message: ' + message);
event.source.postMessage(message, event.origin);
});
Related
I am building a website based on web socket communication. Its is working fine until iOS 14 but started breaking from iOS 15. Web socket java script client is able to open connection to server, but upon trying to send a message, the connection is getting closed. Following is my html and JS code.
function start_websocket() {
connection = new WebSocket("wss://localhost/wss/");
connection.onopen = function () {
console.log('Connection Opened');
};
connection.onerror = function (error) {
console.log('WebSocket Error ' + error);
};
connection.onclose = function(){
console.log("Closed");
};
connection.onmessage = function (e) {
console.log("Message Received :" + e.data);
};
}
function myFunction() {
var testText = document.getElementById("testText");
if (testText.value != "" && connection.readyState === connection.OPEN) {
connection.send("Test");
}
}
start_websocket();
myFunction() is an on-click event of a button.
A Java Websocket server is used, which will decode and send the messages based on the Data framing in https://datatracker.ietf.org/doc/html/rfc6455#section-5.
Saw different articles on the Web, but didn't found a solution to this issue. Any suggestions are much appreciated. Looking forward for your answers
Thanks in advance.
I am trying to get my proxy chrome extention to keep on/off after closing using chrome.local.storage. This does not seem to work, can anyone give some examples on how to get this kind of code working?
Right now my pac proxy works and turns on and off. The local storage does not seem to work at all, but I followed all the examples on the developer.chrome website. That does not work.
var channels;
var ny;
function endvpn() {
// turn off vpn
var config = {
mode: "pac_script",
pacScript: {
data: "function FindProxyForURL(url, host) {\n" +
" if (host == 'google.com /*')\n" +
" return 'PROXY blackhole:80';\n" +
" return 'DIRECT';\n" +
"}"
}
};
chrome.storage.local.set({ny: false});
// change vpn button
document.getElementById("vpnbtn").innerHTML = "Start Vpn";
// turn off event lisner for endvpn and start event listner to go back to startvpn
document.getElementById('vpnbtn').removeEventListener('click', endvpn, false);
document.getElementById("vpnbtn").addEventListener("click", startvpn);
}
function startvpn() {
// turn on vpn
var config = {
mode: "pac_script",
pacScript: {
data: "function FindProxyForURL(url, host) {\n" +
" if (host == 'google.com /*')\n" +
" return 'PROXY blackhole:80';\n" +
" return 'PROXY 209.127.191.180:80';\n" +
"}"
}
};
chrome.storage.local.set({ny: true});
// change vpn button
document.getElementById("vpnbtn").innerHTML = "Stop Vpn";
// turn off event lisner for startvpn and start event listner to go back to endvpn
document.getElementById('vpnbtn').removeEventListener('click', startvpn, false);
document.getElementById("vpnbtn").addEventListener("click", endvpn);
}
var rez = chrome.storage.local.get(ny);
alert(rez);
// start at startvpn
document.getElementById("vpnbtn").addEventListener("click", startvpn);
Most apis within Chrome extensions are asyncronous. See the documentation here. You can provide a callback as the second argument to the 'get' function where you can use the variable:
chrome.storage.local.get('ny', function(result){
alert(result.ny);
});
I'm trying to implement DeviceOrientationEvent and DeviceMotionEvent on my website for a 3D effect. However, the console doesn't log any info and apparently iOS 13 requires a user set permission to start doing this. I can't seem to figure out how to set it up properly.
I've done some research and this is what I found: https://github.com/w3c/deviceorientation/issues/57#issuecomment-498417027
All other methods provided online are not usable anymore sadly.
window.addEventListener('deviceorientation', function(event) {
console.log(event.alpha + ' : ' + event.beta + ' : ' + event.gamma);
});
I get the following error message:
[Warning] No device motion or orientation events will be fired until permission has been requested and granted.
As of iOS 13 beta 2, you need to call DeviceOrientationEvent.requestPermission() to access to gyroscope or accelerometer. This will present a permission dialog prompting the user to allow motion and orientation access for this site.
Note that this will not work if you try to call it automatically when the page loads. The user needs to take some action (like tapping a button) to be able to display the dialog.
Also, the current implementation seems to require that the site have https enabled.
For more information, see this page
if ( location.protocol != "https:" ) {
location.href = "https:" + window.location.href.substring( window.location.protocol.length );
}
function permission () {
if ( typeof( DeviceMotionEvent ) !== "undefined" && typeof( DeviceMotionEvent.requestPermission ) === "function" ) {
// (optional) Do something before API request prompt.
DeviceMotionEvent.requestPermission()
.then( response => {
// (optional) Do something after API prompt dismissed.
if ( response == "granted" ) {
window.addEventListener( "devicemotion", (e) => {
// do something for 'e' here.
})
}
})
.catch( console.error )
} else {
alert( "DeviceMotionEvent is not defined" );
}
}
const btn = document.getElementById( "request" );
btn.addEventListener( "click", permission );
Use an element on your page to use as the event trigger and give it an id of "request".
This will check for https and change it if required before requesting API authorization.
Found this yesterday but do not remember the URL.
You need a click or a user gesture to call the requestPermission().
Like this :
<script type="text/javascript">
function requestOrientationPermission(){
DeviceOrientationEvent.requestPermission()
.then(response => {
if (response == 'granted') {
window.addEventListener('deviceorientation', (e) => {
// do something with e
})
}
})
.catch(console.error)
}
</script>
<button onclick='requestOrientationPermission();'>Request orientation permission</button>
Note : if you click on cancel on the permission prompt and want to test it again, you will need to quit Safari and launch it back for the prompt to come back.
On Xamarin iOS (Xamarin.Forms) you can inject the permission request script with the EvaluateJavaScript method on the WkWebView when it is ready:
webView.EvaluateJavaScript("DeviceMotionEvent.requestPermission().then(response => { if (response == 'granted') {window.addEventListener('devicemotion', (e) => {})}}).catch(console.error)");
If using a custom WkWebView renderer (must implement IWKUIDelegate if this bug is still around https://bugs.webkit.org/show_bug.cgi?id=203287) the script can be injected when setting the webView control in OnElementChanged
Example:
// do this when setting up the webview control in OnElementChanged
//enable device motion sensors permission script:
//https://medium.com/flawless-app-stories/how-to-request-device-motion-and-orientation-permission-in-ios-13-74fc9d6cd140
var source =
"function requestSensorPermission() {" +
" if (typeof(DeviceMotionEvent) !== 'undefined' && typeof(DeviceMotionEvent.requestPermission) === 'function') {" +
" DeviceMotionEvent.requestPermission() .then(response => {" +
" if (response == 'granted') { " +
" window.addEventListener('devicemotion', (e) => { })" +
" }" +
" }).catch(console.error)" +
" }" +
"}";
var script = new WKUserScript(new NSString(source), WKUserScriptInjectionTime.AtDocumentEnd, true);
wkWebView.Configuration.UserContentController.AddUserScript(script);
Then you can call yourCustomWebView.EvaluateJavaScript("requestSensorPermission()") in your code behind when yourCustomWebView is ready.
EvaluateJavaScript:
https://learn.microsoft.com/en-us/dotnet/api/webkit.wkwebview.evaluatejavascript?view=xamarin-ios-sdk-12
Custom WkWebView Renderer: https://learn.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/custom-renderer/hybridwebview#create-the-custom-renderer-on-ios
This is not really an answer, but something to consider if using DeviceMotion on WKWebView.
On Xcode 13 you can use this new WKUIDelegate. You'll still need to request the permission as the other answers mention, but it will not prompt the user for the permission, will directly grant it.
#available(iOS 15, *)
func webView(_ webView: WKWebView,
requestDeviceOrientationAndMotionPermissionFor origin: WKSecurityOrigin,
initiatedByFrame frame: WKFrameInfo,
decisionHandler: #escaping (WKPermissionDecision) -> Void) {
decisionHandler(.grant)
}
My server is firing an event to client2 on some request by client1.The fired event is captured correctly by client2.
See the below code:
'experimentService.experimentPermissionChangedByOwner subscribe': function(eventName, event){
if(this.resource.id == event.eventData.resource) {
if (event.eventData.permissionType == "unshare") {
message = this.resource.name +" has been unshared by the owner: "+event.eventData.ownerUsername+". "+messagePart2;
this.openWorkspaceObject({id: event.eventData.dashboardId, namespace: "bjkbb", type: "jhvhhkk" });
}
else {
message = "Owner: "+event.eventData.ownerUsername+" changed permission of "+ this.resource.name +" to "+ event.eventData.permissionType +". ";
if (event.eventData.permissionType == "view") {
message += messagePart2;
}
this.publish("elements.atlas.resource-page-modified", this.resource);
}
this.openDialog({
dialogClass: elements.AlertCollaborators,
message: message
});
}
this.publish("event.ack", {eventId: event.id});
},
The above code is going to create a small dialog box with a message. Now the problem is on refreshing the browser, it again goes into the subscribe function. I dnt know how to handle this? Moroever after putting debug points I saw that it does not go into publish for this method. Then how does the subcribe capture it again??
We have an app that records audio, making use of the PhoneGap Media API and in iOS's case the File API.
When the user clicks the Accept & Upload button, the app moves that file to the server making use of PhoneGap's File.FileTransfer() method.
Works well with iOS, Android not so much.
When I connect my Android device to my computer and mount as a drive, I can see that the file is getting created at the root which is where it should be.
After the audio file has been created, I'm able to play the file on my device from the location stored in the global var fullRecordPath which = recording.wav
When I attempt to point File.FileTransfer() at that came path I'm getting Error Code = 1 which I understand is File Not Found
Code Handling the Accept & Upload tap event:
$('#btnAcceptUpload').live('tap',function () {
if(isIOS){
thisFileToUpload = fullRecordPath;
} else {
// thisFileToUpload = './'+fullRecordPath; //doesn't work
// thisFileToUpload = 'file:///'+fullRecordPath; //doesn't work
thisFileToUpload = fullRecordPath; //doesn't work
}
var options = new FileUploadOptions();
msg = '';
options.fileKey="file";
msg += "options.fileKey = "+options.fileKey+"\n";
options.fileName=thisFileToUpload.substr(thisFileToUpload.lastIndexOf('/')+1);
msg += "options.fileName = "+options.fileName+"\n";
options.mimeType='audio/wav';
options.chunkedMode = false;
msg += "options.mimeType = "+options.mimeType+"\n";
msg += "thisFileToUpload = "+thisFileToUpload;
alert(msg);
var ft = new FileTransfer();
ft.upload(thisFileToUpload, "http://10.0.17.121/~email/ttmovefiles.php", fileUploadSuccess, fileUploadFailure, options);
});
Success Callback:
function fileUploadSuccess(r) {
console.log("Code = " + r.responseCode);
console.log("Response = " + r.response);
console.log("Sent = " + r.bytesSent);
alert(r.response);
}
Failure Callback:
function fileUploadFailure(error){
alert("An error has occurred: Code = " + error.code);
}
Thanks for looking.
Alright, alright. I figured this one out. I promise I'll come back through and tighten this one down later, but wanted to get it documented so I might end helping another.
in iOS to create a new piece of media you have no choice, you gotta use the File api. This same fully qualified spot in the filesystem was moved in to the same global var which the Media.play() method played nicely with... in iOS.
Not sure why it works this way, but with Android, Media.play() doesn't like the fully qualified path passed in to it. It just wants the filename and it apparently searches from the root.
File.FileTransfer.upload() always wants the fully qualified path of the asset to upload, regardless iOS or Android.
To Make this work:
I used the File API to create the file that the audio Media then uses to move the recording in to. I set 2 global vars: one for playing the audio on the device fullRecordPath and the other for uploading fullUploadPath.
Here's the function the creates the file, invokes the media API and sets the global vars that Android wants:
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function(fileSystem){
fileSystem.root.getFile(recordFileName, {
create: true,
exclusive: false
}, function(fileEntry){
alert("---------> Android File " + recordFileName + " created at " + fileEntry.fullPath);
fullRecordPath = recordFileName;
fullUploadPath = fileEntry.fullPath;
mediaVar = new Media(recordFileName, function(){
alert("Android media created successfully");
}, androidMediaCreateFailure, mediaStatusCallback); //of new Media
onMediaCreated();
}, androidMediaCreateFailure); //of getFile
}, androidMediaCreateFailure); //of requestFileSystem
Here's the code to play that media back
function playAudio() {
var my_media = new Media(fullRecordPath,
// success callback
function () {
console.log("playAudio():Audio Success");
},
// error callback
function (err) {
console.log("playAudio():Audio Error: " + err.code);
exposeObject(err);
});
my_media.play();
}
Here's the code to upload
$('#btnAcceptUpload').live('tap',function () {
if(isIOS){
thisfullUploadPath = fullRecordPath;
} else {
thisfullUploadPath = fullUploadPath;
}
var options = new FileUploadOptions();
msg = '';
options.fileKey="file";
msg += "options.fileKey = "+options.fileKey+"\n";
options.fileName=thisfullUploadPath.substr(thisfullUploadPath.lastIndexOf('/')+1);
msg += "options.fileName = "+options.fileName+"\n";
options.mimeType='audio/wav';
options.chunkedMode = false;
msg += "options.mimeType = "+options.mimeType+"\n";
msg += "thisfullUploadPath = "+thisfullUploadPath;
alert(msg);
var ft = new FileTransfer();
ft.upload(thisfullUploadPath, "http://10.0.17.121/~email/ttmovefiles.php", fileUploadSuccess, fileUploadFailure, options);
});
On android you need to resolveFileSystem
window.resolveLocalFileSystemURI(FILEURI, function(msg){
// success call msg.fullPath
}, function(){
// FAIL
});