I have a problem with Java application and Google Chrome due to NPAPI deprecation..
Reading some articles and blogs, I've found a "solution" : Native Messaging.
But all the examples were made in C++/C#/Python, and for Java there is nothing..
I would like if someone could help me with this..
Here's my schema (see image):
Google chrome Extension -> Native messaging -> Java App (jar)
Problem:
The extension calls the Java app, the Java app runs but doesn't receive anything and when it returns, nothing comes to extension.
Here's my code:
Chrome extension
background.js:
chrome.runtime.onConnect.addListener(function(port) {
port.onMessage.addListener(
function(message) {
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
console.log( 'background.js received msg [' + message.text + ']');
console.log( 'port.postMessage({content: "generated by background.js"}); to [' + tabs[0].id + "/" + tabs[0].url + ']');
chrome.runtime.sendNativeMessage('cnb.digitalsigning',message,function(response) {
console.log("Received from native " + response);
});
chrome.tabs.sendMessage(tabs[0].id, {content: "generated by background.js"});
});
return true;
});
port.onDisconnect.addListener(function() {
console.log("Background.js Port disconnected");
});
});
//native messaging
content_script.js
window.addEventListener("message", function(event) {
// We only accept messages from ourselves
if (event.source != window)
return;
if (event.data.type && (event.data.type == "DIGITAL_SIGNER_MSG")) {
console.log("Content script received from webpage: " + event.data.text);
console.log('calling port.postMessage(event.data.text); ...' + event.data.text );
port = chrome.runtime.connect();
port.postMessage({text: event.data.text});
}
}, false);
chrome.runtime.onMessage.addListener(
function(response, sender, sendResponse) {
alert("receiving response from extension" + response.content );
});
manifest.json
{
"name": "Test",
"description": "Test",
"version": "0.1",
"manifest_version": 2,
"background": {
"persistent" : true,
"scripts": ["background.js"]
},
"content_scripts": [
{
"matches": ["*://*/*"],
"js": ["content_script.js"]
}
],
"permissions": [
"nativeMessaging"
]
}
HTML
<html>
<script>
function myFunc(){
console.log('call func');
window.postMessage({ type: "DIGITAL_SIGNER_MSG", text: "do it, baby!" }, "*");
console.log('func called');
}
</script>
<body>
<div>Page</div>
<form>
<button id="caller" onclick="myFunc()">Call Extension</button>
<div id="reponseDiv" style="border: 3px; border-color: blue;">NO RESPONSE LOADED</div>
</form>
</body>
</html>
Host
installReg.bat
REG ADD "HKCU\Software\Google\Chrome\NativeMessagingHosts\digitalsigning" /ve /t REG_SZ /d "%~dp0digitalsigning.json" /f
pause
launch.bat
C:\location\to\Java\jre\bin\java.exe -cp C:\component\target\java.jar com.org.App
pause
digitalsigning.json
{
"name": "digitalsigning",
"description": "digitalsigning",
"path": "c:\\place\\launch.bat",
"type": "stdio",
"allowed_origins": [
"chrome-extension://<GOOGLE EXTENSION ID GENERATED>/"
]
}
The aplication contains a Main that captures the message using System.in.read and response to extension using System.out.write..
How could I do this communication?
Is this the correct way to start the java app?
At https://stackoverflow.com/a/25617143/865284 you can see how to send data in a proper way. System.in should be the correct way, but by now, i didn't find a way to receive data in java.
Note also this post, where sent and returned messages are sent successfully using only a few simple lines of code: https://stackoverflow.com/a/33113627. It should make it clear what the basic requirements of returned messages are.
You can take a look at https://github.com/Cosium/web-native-messaging-host .
It is a java library allowing to turn any JVM application into a Web Native Messaging Host .
Related
I recently got into front end developpement to make an interface for a nodejs server hosted on a raspberry pi.
I heard of progressive web app and wanted the user to be able to install it on his phone.
So here are the manifest and the service worker script.
Manifest:
{
"name": "Philips D6330",
"short_name": "Philips D6330",
"description": "A control app for the Philips D6330",
"icons": [
{
"src": "https://192.168.1.26/cdn/favicon.png",
"sizes": "512x512",
"type": "image/png"
}
],
"start_url": "https://192.168.1.26",
"display": "fullscreen",
"orientation": "portrait",
"theme_color": "#333333",
"background_color": "#333333",
"scope": "/"
}
Service Worker:
const CACHE_NAME = 'cache';
const CACHE = [
'/',
'/cdn/offline.html',
'/cdn/style.css',
'/cdn/favicon.png',
'/cdn/linetoB.ttf',
'/cdn/linetoL.ttf',
'/cdn/neon.ttf',
'/cdn/not.png',
'/cdn/next.png',
'/cdn/pause.png',
'/cdn/play.png',
'/cdn/previous.png',
'/cdn/dots.png',
'/cdn/rfid.png'
];
self.addEventListener('install', function(event) {
event.waitUntil(
caches.open(CACHE_NAME)
.then(function(cache) {
return cache.addAll(CACHE)
})
.then(self.skipWaiting())
)
})
self.addEventListener('fetch', function(event) {
if (event.request.mode === 'navigate') {
event.respondWith(
fetch(event.request)
.catch(() => {
return caches.open(CACHE_NAME)
.then((cache) => {
return cache.match('/cdn/offline.html');
})
})
);
}
else {
event.respondWith(
fetch(event.request)
.catch(() => {
return caches.open(CACHE_NAME)
.then((cache) => {
return cache.match(event.request)
})
})
);
}
})
self.addEventListener('activate', function(event) {
event.waitUntil(
caches.keys()
.then((keyList) => {
return Promise.all(keyList.map((key) => {
if (key !== CACHE_NAME) {
console.log('[ServiceWorker] Removing old cache', key)
return caches.delete(key)
}
}))
})
.then(() => self.clients.claim())
)
})
I think also relevant to tell you that all of this happens on my local network so my node server uses https with a self-signed certificate made using this tutorial : https://medium.com/#tbusser/creating-a-browser-trusted-self-signed-ssl-certificate-2709ce43fd15
But even tho it's a self-signed certificate, the service worker seem to registers well on firefox and chrome, as it stores the files and displays the offline page when offline.
Here is my problem :
when I want to install it from the desktop version of chrome I can but not chrome mobile (or samsung internet)...
here is the piece of code i use to make it instalable :
<script defer>
window.addEventListener('beforeinstallprompt', (event) => {
console.log('👍', 'beforeinstallprompt', event);
// Stash the event so it can be triggered later.
window.deferredPrompt = event;
});
butInstall.addEventListener('click', () => {
console.log('👍', 'butInstall-clicked');
const promptEvent = window.deferredPrompt;
if (!promptEvent) {
// The deferred prompt isn't available.
return;
}
// Show the install prompt.
promptEvent.prompt();
// Log the result
promptEvent.userChoice.then((result) => {
console.log('👍', 'userChoice', result);
// Reset the deferred prompt variable, since
// prompt() can only be called once.
window.deferredPrompt = null;
});
});
window.addEventListener('appinstalled', (event) => {
console.log('👍', 'appinstalled', event);
});
</script>
It comes from here https://web.dev/codelab-make-installable/
Here is a screenshot of the before install prompt event with the lighthouse report if it can help (by the way the plus sign in the url shows it's working):
console log infos
But on mobile the plus sign doesn't show up and nothing happens when I click the button... And as I don't have acces to the console I can't see any errors...
------ Edit ------
After using alert to log what the console says, I think the problem comes from the service worker does register well because I get this :
"ServiceWorker registration failed: SecurityError: Failed to register a ServiceWorker for scope ('https://192.168.1.26/') with script ('https://192.168.1.26/sw.js'): An SSL certificate error occurred when fetching the script.".
Is there a way to make the browser trust my self-singed certificate ?
Any help, suggestion or comment is welcome ^^
Its a .webmanifest and you dont match the criteria. You need an 512x512 AND an 192x192 icon.
As start_url i would just use /?source=pwa
"icons": [
{
"src": "icon.png",
"type": "image/png",
"sizes": "192x192"
},
{
"src": "big_icon.png",
"type": "image/png",
"sizes": "512x512"
}
],
"start_url": "/?source=pwa",
After that you need to link your webmanifest with <link>
<link rel="manifest" href="/manifest.webmanifest">
Check if the paths are all correct.
Here is my own little "library" to abstract things: https://github.com/ilijanovic/serviceHelper (its under development tho)
If you met all criteria, then you can make your app installable
Here its how it works with my library. You instantiate the class and pass the path to the service worker.
var sh = new ServiceHelper("./sw.js");
sh.init().then(response => {
console.log("Initialized");
})
sh.on("notinstalled", (e) => {
console.log("App is not installed");
//do some stuff. For example enable some button
//button.classList.remove("disabled");
})
butInstall.addEventListener('click', () => {
sh.installApp().then(e => {
// e = user choice event
console.log(e);
}).catch(err => {
// error if the app is already installed
console.log(err);
})
I'm trying to create a very simple Chrome extension that will allow me to highlight a word on a webpage, right click to open the context menu, and then search it on a database called Whitaker's Words by simply appending the word to the search URL. I'm continuing to receive
"Unchecked runtime.lastError: Could not establish connection. Receiving end does not exist."
as an error every time I run the code and attempt to use the context menu.
At the moment, I have already taken the steps to disable all other extensions and I attempted to use the port documentation on the Chrome Messaging Docs but I wasn't able to resolve the issue that way.
background.js
chrome.contextMenus.create({
title: "Search Whitaker's Words",
contexts: ["selection"]
});
chrome.contextMenus.onClicked.addListener(function() {
chrome.runtime.sendMessage({ method: "getSelection" }, function (response) {
sendToWW(response.data);
});
});
function sendToWW(selectedText) {
var serviceCall = 'http://archives.nd.edu/cgi-bin/wordz.pl?keyword=' + selectedText;
chrome.tabs.create({ url: serviceCall });
}
Here, I create a context menu and when the menu item is clicked, I send a message to the context script asking for the highlighted selection. I then return this to another function in background.js that will create a new tab with the search query.
content.js
chrome.runtime.onMessage.addListener(function (message) {
if (message.method === "getSelection"){
var word = window.getSelection().toString().trim();
console.log(word);
chrome.runtime.sendMessage({ data: word });
}
else
chrome.runtime.sendMessage({}); // snub them.
});
I listen here for the message and then take a selection from the window, trim, and send it back.
manifest.json
{
"manifest_version": 2,
"name": "Latinate",
"version": "0.1",
"description": "Aid in Latin translation using Whitaker's Words",
"content_scripts": [
{
"matches": [
"<all_urls>"
],
"js": [
"jquery-3.4.1.min.js",
"content.js"
]
}
],
"background": {
"scripts": [
"background.js"
]
},
"permissions": [
"contextMenus",
"tabs"
],
"browser_action": {
"default_icon": "icon.png",
"default_popup": "popup.html"
}
}
Any and all help would be appreciated! I've tried nearly everything I could find that seemed to apply.
The error message says there is no message listener on the other side. And indeed there is none because a message listener is a function registered with chrome.runtime.onMessage.addListener - in your extension only the content script has such a listener.
Instead of sending a new message back, send the response using sendResponse function which is passed as a parameter to the onMessage listener
(see also the messaging tutorial).
Another problem is that to send a message to a tab you need to use a different method: chrome.tabs.sendMessage with a tab id as the first parameter.
background script:
chrome.contextMenus.onClicked.addListener((info, tab) => {
chrome.tabs.sendMessage(tab.id, {method: 'getSelection'}, response => {
sendToWW(response.data);
});
});
content script:
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
if (message.method === 'getSelection') {
var word = window.getSelection().toString().trim();
console.log(word);
sendResponse({ data: word });
} else {
sendResponse({});
}
});
I use a chrome extension with a popup to inject a website and hide some divs.
The problem now is, I want to open a new tab with the
url: https://app.example.de/dashboard/ and inject the style with my contentscript.js
Another problem is: Sometimes the application reloads the page. After this, all injections are lost. Is there any chance to inject allways the https://app.example.de/dashboard/ without click on the popup.html-Button?
The following code works fine, if the page is already open.
manifest.json
{
"name": "example stealth mode",
"version": "1.1",
"description": "lorem ipsum",
"browser_action": {
"default_icon": "icon-on.png",
"default_popup": "popup.html",
"default_title": "example stealth mode"
},
"manifest_version": 2,
"content_scripts": [
{
"matches": ["https://*.app.example.de/*"],
"js": ["jquery-1.11.0.min.js", "background.js"]
}
],
"background": {
"scripts": ["background.js"]
},
"permissions": [
"tabs", "https://*.app.example.de/*"
]
}
popup.js
document.addEventListener('DOMContentLoaded', function () {
document.getElementById('On').addEventListener('click', clickHandlerOn);
})
// An
function clickHandlerOn(e) {
chrome.extension.sendMessage({directive: "popup-click"}, function(response) {
this.close(); // close the popup when the background finishes processing request
});
}
background.js
chrome.extension.onMessage.addListener(
function(request, sender, sendResponse) {
switch (request.directive) {
case "popup-click":
// execute the content script
chrome.tabs.executeScript(null, { // defaults to the current tab
file: "contentscript.js", // script to inject into page and run in sandbox
allFrames: true // This injects script into iframes in the page and doesn't work before 4.0.266.0.
});
sendResponse({}); // sending back empty response to sender
break;
default:
// helps debug when request directive doesn't match
alert("Unmatched request of '" + request + "' from script to background.js from " + sender);
}
}
);
contenscript
$(document).ready(function() {
$('div#hlXXXContent').hide();
$('#hlYYY').hide();
$('#hlZZZ').hide();
$('h3.hlVVV').append(' Stealth Mode');
});
popup.html
<li><button class="hl123" id="On"><span class="hlSubmenuSelected">Stealthmode on</span</button></li>
The filename contentscript.js is odd because it's not a content script as you're using it. Why don't you try experimenting with run_at and have something load on each target page load, and that'll be your opportunity for your code to decide whether to do more things to the page.
I like to click my chrome extension and it takes the current tabs url and inserts it into a MySQL database. It seems I have to use an xhr, however I a loose grasp of how it works. I also slightly get the idea Chrome Extension → Web App API → MySQL.
So far I have a working chrome extension that grabs the current tabs url and displays it and a php file connecting to my database. However I could use some help getting to url variable to a Web API then to my php file.
Lastly, I am a bit of a newbie so I apologize if this is questioned poorly.
Edit
Here is my code and more details...
currentUrl.js
//grab the current url
chrome.tabs.getSelected(null, function(tab) {
var tabId = tab.id;
tabUrl = tab.url;
document.write(tabUrl);
});
popup.html
<!doctype html>
<html>
<head>
<script src="currentUrl.js"></script>
<script language="javascript" type="text/javascript">
</head>
</html>
insertdb.php
<?php
$con=mysqli_connect("localhost","root","my_pw","my_db");
// Check connection
if (mysqli_connect_errno())
{
echo "Failed to connect to MySQL: " . mysqli_connect_error();
}
mysqli_query($con,"INSERT INTO urlHistory (Urls)
VALUES ('Url'");
mysqli_close($con);
?>
manifest.json
{
"manifest_version": 2,
"name": "Current Url",
"description": "Grab tab's current url",
"version": "1.0",
"browser_action": {
"default_icon": "url_icon.png",
"default_popup": "popup.html"
},
"permissions": [
"tabs"
// dont't I have to put something here?
]
}
You could use XHR to send the URL over to your server where insertdb.php will be listening for and storing URLs in the DB.
Some more info on relevant concepts:
MySQLi prepared statements
XMLHttpRequests
browserAction
Sample code:
(The code below is for demonstration only and it does not take into account basic concepts, such as input validation, user authorization/authentication, error handling etc (all of which are essential for a production-ready solution).)
In insertdb.php:
<?php
if (isSet($_POST['url'])) {
$con = mysqli_connect('localhost', 'root', 'my_pw', 'my_db');
...
$stmt = mysqli_prepare($con, 'INSERT INTO urlHistory (Urls) VALUES (?)');
mysqli_stmt_bind_param($stmt, 's', $_POST['url']);
mysqli_stmt_execute($stmt);
mysqli_stmt_close($stmt);
mysqli_close($con);
}
?>
In background.js:
function sendCurrentUrl(url) {
var req = new XMLHttpRequest();
req.addEventListener('readystatechange', function (evt) {
if (req.readyState === 4) {
if (req.status === 200) {
alert('Saved !');
} else {
alert("ERROR: status " + req.status);
}
}
});
req.open('POST', 'https://your_domain/your/path/insertdb.php', true);
req.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
req.send('url=' + encodeURIComponent(url));
}
chrome.browserAction.onClicked.addListener(function (tab) {
sendCurrentUrl(tab.url);
});
In manifest.json:
{
"manifest_version": 2,
"name": "Test Extension",
"version": "0.0",
"background": {
"persistent": false,
"scripts": ["background.js"]
},
"permissions": [
"activeTab",
"https://your_domain/*"
]
}
AIM : when ever new tab is opened extension makes a request with the url to server and get the response and change the icon color .
background.js :
chrome.tabs.onUpdated.addListener(function (tabId, changeInfo, tab)
{
url = "http://localhost/test.php?"+ $.param({"url":tab.url});
$.get(url, function(responseText) {
console.log("sent data");
});
});
manifest.json :
..."background": { "scripts": ["background.js"] ,"persistent": false },
"permissions": ["tabs","http://localhost/", "http://*/*"],....
this doesnt works .
but when binded with a button on extension page as :
function send_url(){
chrome.tabs.getSelected(null,function(tab){
url = "http://localhost/test.php?"+ $.param({"url":tab.url});
$.get(url, function(responseText) {
console.log("url sent ");
});
});
}
this sends the url to my local server !
is there any thing which is missing with background.js
This is what i was looking for :
"background": { "scripts": ["assets/js/jquery.min.js","background.js"] ,"persistent": false },