Reputation: 21
I try to do a chrome extension that call to a java code in my PC. The call works fine, the code executes, but I try to return variables to chrome extension but don't work. I see in the console that the listener onDisconect
write a console message, but the listener onMessage
don't. I don't know the problem.
Here is my code in the chrome extension:
Manifest JSON
{
"name": "Prueba native message",
"version": "1.0",
"manifest_version": 2,
"description": "Chrome extension interacting with Native Messaging and localhost.",
"app": {
"background": {
"scripts": ["background.js"]
}
},
"icons": {
},
"permissions": [
"nativeMessaging"
]
}
background.js
var port = chrome.runtime.connectNative('com.app.native');
function message(msg) {
console.warn("Received" + msg);
}
function disconect() {
console.warn("Disconnected");
}
console.warn("se ha conectado");
port.onMessage.addListener(message);
port.onDisconnect.addListener(disconect);
port.postMessage({text: "Hello, my_application"});
console.warn("message send");
And here my local files.
.bat
cd C:\Users\pc\IdeaProjects\eDNI\out\production\code && java Main
Main.java
public class Main {
public static void main(String argv[]) throws IOException {
System.out.println("{\"m\":\"hi\"");
}
}
In this code I only try to return a simple message to the extension.
Upvotes: 2
Views: 2728
Reputation: 57
I have been using my native host on chrome for a while. Here is how developed and pay attention to the previous comment on sending data back in byte arrays. That part is critical. The projects native host and the extension part as well as the document are also available on this github
Extension + Doc: https://github.com/esabilbulbul/ss-ext-barcode-web Native Host (java): https://github.com/esabilbulbul/ss-app-barcode-nativehost-java Native Host (cpp): https://github.com/esabilbulbul/ss-app-barcode-nativehost-cpp
Manifest jSON
{
"manifest_version": 2, "version": "1.0", "name": "Hello World 3", "icons":
{
"128":"icons/icon128.png", "48":"icons/icon48.png", "16":"icons/icon16.png"
}, "page_action": {
"default_icon":"/icons/icon16.png",
"default_popup":"popup.html" },
"content_scripts": [
{
"matches":[
"http://localhost:8080/*/*",
"http://localhost:8080/ss-web- client/SHIPSHUK/WEBSITE/pages/merchant/reports/posdekont/mybizstats.html"
], "js":["content.js"]
} ],
"background": {
"scripts":["background.js"],
"persistent": false },
"permissions": [
"nativeMessaging", "activeTab",
"tabs", "http://localhost:8080/*/*"
] }
"externally_connectable": {
"matches": [ ],
"http://localhost:8080/*/*"
"ids":[ "fhbnbigbjcmhllmfccoomobllianhofe", "*"
] },
I send a message from page to the extension with this code
var editorExtensionId = 'fhbnbigbjcmhllmfccoomobllianhofe';
//chrome.runtime.sendMessage({todo: "showPageAction", value: 'test'}); //window.postMessage({ type: "showPageAction", todo: "showPageAction", text: "Hello from the webpage!" }, "*");
// Make a simple request:
chrome.runtime.sendMessage(editorExtensionId, {todo: "showPageAction", value: 'test2'});
NATIVE HOST REGISTRY ON CHROME: You also need to register your native host for chrome. If you are on Windows, do it with regadd, if you are on linux or mac create a json file under nativemessaginghosts folder under chrome. In my case the folder was /Users/esabil/Library/Application Support/Google/Chrome/NativeMessagingHosts
Final part is the NATIVE HOST APP. You can do this with any language as long as you use stdio. I did it with java and cpp. Here is my java part
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package nativehost;
import java.io.IOException;
/**
*
* @author esabil
*/
public class main {
/**
* @param args the command line arguments
*
*
* This is NATIVE MESSAGING HOST of Chrome Extension for Barcode Printing (SHIPSHUK)
*
*/
public static void main(String[] args)
{
// TODO code application logic here
//System.out.println("NativeHost app is starting");
String sIncomingMsg = receiveMessage();
String sOutgoingMsg = "{\"text\":\"java host\"}";
sendMessage(sOutgoingMsg);
}
//Convert length from Bytes to int
public static int getInt(byte[] bytes)
{
return (bytes[3] << 24) & 0xff000000|
(bytes[2] << 16)& 0x00ff0000|
(bytes[1] << 8) & 0x0000ff00|
(bytes[0] << 0) & 0x000000ff;
}
// Read an input from Chrome Extension
static public String receiveMessage()
{
byte[] b = new byte[4];
try
{
System.in.read(b);
int size = getInt(b);
byte[] msg = new byte[size];
System.in.read(msg);
// make sure to get message as UTF-8 format
String msgStr = new String(msg, "UTF-8");
return msgStr;
}
catch (IOException e)
{
e.printStackTrace();
return null;
}
}
public static byte[] getBytes(int length)
{
byte[] bytes = new byte[4];
bytes[0] = (byte) ( length & 0xFF);
bytes[1] = (byte) ((length>>8) & 0xFF);
bytes[2] = (byte) ((length>>16) & 0xFF);
bytes[3] = (byte) ((length>>24) & 0xFF);
return bytes;
}
static public void sendMessage(String pMsg)
{
try
{
System.out.write(getBytes(pMsg.length()));
byte[] bytes = pMsg.getBytes();
System.out.write(bytes);
}
catch (IOException ex)
{
ex.printStackTrace();
}
}
}
Upvotes: 0
Reputation: 24098
Native messaging protocol
Chrome starts each native messaging host in a separate process and communicates with it using standard input (stdin) and standard output (stdout). The same format is used to send messages in both directions: each message is serialized using JSON, UTF-8 encoded and is preceded with 32-bit message length in native byte order. The maximum size of a single message from the native messaging host is 1 MB, mainly to protect Chrome from misbehaving native applications. The maximum size of the message sent to the native messaging host is 4 GB.
Source: Native Messaging Protocol
The first four bytes need to be the length of the message. You need to convert the message length, which is an integer, to a byte array:
Option 1: Using java.nio.ByteBuffer class
public byte[] getBytes(int length) {
ByteBuffer b = ByteBuffer.allocate(4);
b.putInt(length);
return b.array();
}
Option 2: Manual:
public byte[] getBytes(int length) {
byte[] bytes = new byte[4];
bytes[0] = (byte) (length & 0xFF);
bytes[1] = (byte) ((length >> 8) & 0xFF);
bytes[2] = (byte) ((length >> 16) & 0xFF);
bytes[3] = (byte) ((length >> 24) & 0xFF);
return bytes;
}
Write out the message length and then the message content in bytes.
String message = "{\"m\":\"hi\"}";
System.out.write(getBytes(message.length()));
System.out.write(message.getBytes("UTF-8"));
System.out.flush();
Update:
It also looks like you are missing the interface type that needs to be specified in your manifest file.
Add this: "type": "stdio"
Upvotes: 2