Chrome Apps, FileSystem API: chooseEntry method is

2019-09-02 23:08发布

问题:

Edit: Found the error, but can't solve it, see below.

manifest.json

{
    ...
    "offline_enabled": true,
    "app": {
        "background": {
            "persistent": true,
            "scripts": [
                "/js/background.js"
            ]
        }
    },
    "permissions": [
        "notifications",
        "storage",
        {"fileSystem": ["directory"]}
    ]
}

background.js

chrome.app.runtime.onLaunched.addListener(function() {
    window.open('/index.html');
});

index.html

<!DOCTYPE html>
<html>
    <head>
        <title>Achshar Player</title>
        <script src="/js/index.js"></script>
    </head>
    <body>
        <input id="input" type="button">
    </body>
</html>

index.js

window.addEventListener('load', function() {
    document.getElementById('input').addEventListener('click', function() {
        chrome.fileSystem.chooseEntry({type: 'openFile'}, function(readOnlyEntry) {
            console.log(readOnlyEntry);
        });
    });
});

The method is called and so is the callback, but the file choosing dialogue never comes and the readOnlyEntry is undefined when the callback is executed. No errors on the dev tools, I am on 35.0.1916.153 m.

I have tried different variations of manifest declarations for fileSystem but since the function is not undefined in the script execution, the manifest is unlikely to be the issue.

When I use the official example extension of fileSystem API the app works, so the chrome setup isn't the problem either. The problem seem to be my code, but I am lost here.

Edit: I added each file's content

Edit 2: Found the error, now how to solve it?

I tried it in canary and realize the errors are shown via chrome.runtime.lastError and not the normal console. And this is the error I get.

Invalid calling page. This function can't be called from a background page.

But this is not in background.js, this is in index.js which is called from index.html.

回答1:

I just tried this in Chrome, and there doesn't seem to be anything wrong with the code that you've posted. I suspect that there is a problem with the way that you are loading the javascript, or possibly the context that it is running in (foreground page vs. background page)

For instance, if your JavaScript code snippet is actually in main.js, then that will run in the background page, and its window and document elements won't be the ones from your main page.

My test app looks very similar to yours, except that I have left out the main.js file from the manifest, and I have constructed a small index.html file, which loads a foreground.js script instead. This is the complete app:

manifest.json

{
    "manifest_version": 2,
    "name": "Stack overflow question test app",
    "version": "1",
    "offline_enabled": true,
    "app": {
        "background": {
            "persistent": true,
            "scripts": [
                "/js/background.js"
            ]
        }
    },
    "permissions": [
        "notifications",
        "storage",
        {"fileSystem": ["directory"]}
    ]
}

js/background.js

chrome.app.runtime.onLaunched.addListener(function() {
    chrome.app.window.create("index.html");
});

index.html

<!DOCTYPE html>
<html>
    <head>
        <title>TEST</title>
        <script src="js/foreground.js"></script>
    </head>
    <body>
      <input id="input" />
    </body>
</html>

js/foreground.js

window.addEventListener('load', function() {
    document.getElementById('input').addEventListener('click', function() {
        chrome.fileSystem.chooseEntry({type: 'openFile'}, function(readOnlyEntry) {
            console.log(readOnlyEntry);
        });
    });
});

When I run this, I can click on the input element, and I see a file picker. Choosing an entry returns a FileEntry object, which is logged to the console (of the foreground page, not the background page. Right-click in the app window and select "Inspect Element", rather than "Inspect Background Page", to see the foreground console.):

FileEntry {filesystem: DOMFileSystem, fullPath: "/TestFile.rtf", name: "TestFile.rtf", isDirectory: false, isFile: true…} foreground.js:4

Note:

From your original code, it appeared that you were using a framework like jQuery to search for DOM elements within your page. Chrome Apps work just fine with jQuery, but you have to be aware of when you are using a raw DOM Node object, and when you have a wrapped jQuery object.

Specifically, the line

$('input').addEventListener('click', function() {

would have caused you problems.

Replacing it with

document.querySelector('input').addEventListener('click'), function() {

would correctly find the element on the page, and attached the click handler to it.