Marcos Pires
Marcos Pires

Reputation: 21

Java and chrome extension, natives messages

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

Answers (2)

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

Gideon Pyzer
Gideon Pyzer

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

Related Questions