javascript 如何从远程页面访问 phonegap API

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/21984688/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-27 22:09:31  来源:igfitidea点击:

How to get access to phonegap API from a remote page

javascriptandroidioscordovacordova-plugins

提问by riedelinho

I have to following situation: I have a already existing remote webpage and i want to develope an app which uses this page. So far, so good. When I start the app the local index.htmlis loaded and it redirects (window.open target: _self) to the external website. This website is opened in the phonegap webview. On the external website I added the cordova.jsin order to get access to the native phonegap API. But it doesn't work correctly. The deviceReadyevent is triggered correctly, but I have no access to the phonegap API, for example navigator.camera.

我必须遇到以下情况:我已经有一个远程网页,我想开发一个使用此页面的应用程序。到现在为止还挺好。当我启动应用程序时,本地index.html已加载,并将 ( window.open target: _self)重定向到外部网站。这个网站是在phonegap webview中打开的。在外部网站上,我添加了cordova.js以便访问本机 phonegap API。但它不能正常工作。该deviceReady事件被触发正确的,但我没有访问PhoneGap的API,例如navigator.camera。

How can I get it done, to get access to the API?

我怎样才能完成它,以访问 API?

Please do not comment that it will be rejected by AppStore etc. etc.

请不要评论它会被 AppStore 等拒绝。

Thank you for your help!

谢谢您的帮助!

回答by Lentyai

Well, for me the solution was a mixture of several sources, but most of the solution was found here.

好吧,对我来说,解决方案是多种来源的混合,但大部分解决方案都在这里找到。

What you should do is the following:

你应该做的是:

  1. Define your config.xmlto point directly to the remote index.html.

    <content src="http://your-remote-location/index.html" />
    
  2. In your index.htmlany reference to a local android device resource prepend with some unique prefix like **injection**. For instance for cordova.jsyou'll come up with something like:

    <script type="text/javascript" src="**injection**www/cordova.js"></script>
    
  3. Find SystemWebViewClient.javaunder the following location: your-project-location\platforms\android\CordovaLib\src\org\apache\cordova\engine.

  4. Add the following enum declaration in the private members section of the class at the top:

    private enum WebExtension {
        PNG, MP3, MP4, TTF, SVG, JS, ICO, HTML, CSS, EOT, WOFF, JSON;
    }
    
  5. Locate the shouldInterceptRequestmethod and add the following right after the try {line:

    if(url != null && url.contains(INJECTION_TOKEN)) {
        String assetPath = url.substring(url.indexOf(INJECTION_TOKEN) + INJECTION_TOKEN.length(), url.length());
        try {
            String mimeType = "text/plain";
    
            String ext = assetPath.substring(assetPath.lastIndexOf(".") + 1, assetPath.length());
            WebExtension extension = WebExtension.valueOf(ext.toUpperCase());
    
            switch(extension) {
                case PNG:
                    mimeType = "image/png";
                    break;
                case MP3:
                    mimeType = "audio/mpeg";
                    break;
                case MP4:
                    mimeType = "video/mp4";
                    break;
                case TTF:
                    mimeType = "application/x-font-ttf";
                    break;
                case SVG:
                    mimeType = "image/svg+xml";
                    break;
                case JS:
                    mimeType = "application/javascript";
                    break;
                case ICO:
                    mimeType = "image/x-icon";
                    break;
                case HTML:
                    mimeType = "text/html";
                    break;
                case CSS:
                    mimeType = "text/css";
                    break;
                case EOT:
                    mimeType = "application/vnd.ms-fontobject";
                    break;
                case WOFF:
                    mimeType = "application/x-font-woff";
                    break;
                case JSON:
                    mimeType = "application/json";
                    break;
            }
    
            WebResourceResponse response = new WebResourceResponse(
                mimeType,
                "UTF-8",
                parentEngine.webView.getContext().getAssets().open(assetPath)
            );
            return response;
        } catch (IOException e) {
            e.printStackTrace(); // Failed to load asset file
        }
    }
    
  1. 定义您的config.xml以直接指向远程index.html

    <content src="http://your-remote-location/index.html" />
    
  2. 在您index.html对本地 android 设备资源的任何引用中,都带有一些独特的前缀,例如**injection**. 例如,cordova.js你会想出类似的东西:

    <script type="text/javascript" src="**injection**www/cordova.js"></script>
    
  3. SystemWebViewClient.java在以下位置找到:your-project-location\platforms\android\CordovaLib\src\org\apache\cordova\engine

  4. 在顶部类的私有成员部分添加以下枚举声明:

    private enum WebExtension {
        PNG, MP3, MP4, TTF, SVG, JS, ICO, HTML, CSS, EOT, WOFF, JSON;
    }
    
  5. 找到该shouldInterceptRequest方法并在该try {行之后添加以下内容:

    if(url != null && url.contains(INJECTION_TOKEN)) {
        String assetPath = url.substring(url.indexOf(INJECTION_TOKEN) + INJECTION_TOKEN.length(), url.length());
        try {
            String mimeType = "text/plain";
    
            String ext = assetPath.substring(assetPath.lastIndexOf(".") + 1, assetPath.length());
            WebExtension extension = WebExtension.valueOf(ext.toUpperCase());
    
            switch(extension) {
                case PNG:
                    mimeType = "image/png";
                    break;
                case MP3:
                    mimeType = "audio/mpeg";
                    break;
                case MP4:
                    mimeType = "video/mp4";
                    break;
                case TTF:
                    mimeType = "application/x-font-ttf";
                    break;
                case SVG:
                    mimeType = "image/svg+xml";
                    break;
                case JS:
                    mimeType = "application/javascript";
                    break;
                case ICO:
                    mimeType = "image/x-icon";
                    break;
                case HTML:
                    mimeType = "text/html";
                    break;
                case CSS:
                    mimeType = "text/css";
                    break;
                case EOT:
                    mimeType = "application/vnd.ms-fontobject";
                    break;
                case WOFF:
                    mimeType = "application/x-font-woff";
                    break;
                case JSON:
                    mimeType = "application/json";
                    break;
            }
    
            WebResourceResponse response = new WebResourceResponse(
                mimeType,
                "UTF-8",
                parentEngine.webView.getContext().getAssets().open(assetPath)
            );
            return response;
        } catch (IOException e) {
            e.printStackTrace(); // Failed to load asset file
        }
    }
    

The result of all of it will be interception of every resource request and in case it will contain the **injection**string in it, it will cut down the resource location and will request it from local device location under which the application is running. The mimeType is necessary to load the resource in the correct manner by the app browser.

所有这一切的结果将是拦截每个资源请求,如果其中包含**injection**字符串,它将削减资源位置并从应用程序运行的本地设备位置请求它。mimeType 是应用浏览器以正确方式加载资源所必需的。

Hope it helps someone.

希望它可以帮助某人。

回答by jperelli

This plugin solves the problem without having to code yourself an android solution.

这个插件解决了这个问题,而不必自己编写一个 android 解决方案。

https://www.npmjs.com/package/cordova-plugin-remote-injection

https://www.npmjs.com/package/cordova-plugin-remote-injection

https://github.com/TruckMovers/cordova-plugin-remote-injection

https://github.com/TruckMovers/cordova-plugin-remote-injection

The remote injection plugin allows a remote site to interact with cordova's javascript APIs when loaded within your cordova app.

  • Injects cordova and installed plugin JS into the webview for any remotely browsed page allowing them the same access to the cordova object and its plugins as a packaged cordova app.

  • Support for iOS and Android platforms.

远程注入插件允许远程站点在加载到您的cordova 应用程序中时与cordova 的javascript API 进行交互。

  • 将cordova 和已安装的插件JS 注入到任何远程浏览页面的webview 中,允许他们像打包的cordova 应用程序一样访问cordova 对象及其插件。

  • 支持iOS和Android平台。

I tested it and it works just fine. The only thing you need to remember is that you'll need to wait for cordova to be ready, like this:

我测试了它,它工作得很好。您唯一需要记住的是,您需要等待cordova 准备就绪,如下所示:

<html>
  <head>
  </head>
  <body>
    <script>
      document.addEventListener("deviceready", function() {
          document.write("Now you can use plugins"); 
      }, false);
    </script>
  </body>
</html>

回答by Mister Smith

Including the cordova.js script in the remote site is going to be tricky, because there's a different cordova.js for each platform. You could modify the server so that it returns the correct cordova.js based on the user agent, but this is also tricky because it will include this script when you view the site from a mobile browser, and this is undesirable because javascript errors might be shown to the user. Same story when viewing the site from a desktop computer, the cordova.js should not be included.

在远程站点中包含cordova.js 脚本会很棘手,因为每个平台都有不同的cordova.js。您可以修改服务器,使其根据用户代理返回正确的cordova.js,但这也很棘手,因为当您从移动浏览器查看站点时,它会包含此脚本,这是不可取的,因为可能会出现javascript 错误显示给用户。从台式计算机查看站点时的情况相同,不应包含cordova.js。

It looks to me that you have a local web page (with the cordova script included) and from there you change to the remote page (that also includes the script). I'm not sure this page change is going to work. If it worked, you might have to wait for the second deviceready event.

在我看来,您有一个本地网页(包含cordova 脚本),然后从那里切换到远程页面(也包含脚本)。我不确定此页面更改是否会起作用。如果它有效,您可能需要等待第二个 deviceready 事件。

But you can just set the remote site page as the root page in the cordova app, no need for an intermediate "loader" page. Just set it in the config.xml file:

但是您可以将远程站点页面设置为cordova 应用程序中的根页面,不需要中间的“加载程序”页面。只需在 config.xml 文件中设置它:

<content src="http://your.website.fake/index.html" />

You need to make sure that you allow loading your site in the app. In this same file, you should add:

您需要确保允许在应用程序中加载您的网站。在同一个文件中,您应该添加:

<access origin="http://your.website.fake" subdomains="true"/> 

回答by sorin7486

I've had this problem as well and changing things in config.xml(content and access tags) didn't work. I inspected the app while it was running on the phone and I discovered that when I loaded the remote site there were some files missing.

我也遇到过这个问题,更改 config.xml(内容和访问标签)中的内容不起作用。我在手机上运行时检查了该应用程序,发现当我加载远程站点时,缺少一些文件。

First off it's the file called cordova_plugins.jswhich you can find for each platform in the platform folder. Then you also need some plugin specific files. You can find these by doing a build and extracting them from there. For android the path is as follows APK/assets/www/plugins. Just copy the contents on your server and you're good to go.

首先是名为cordova_plugins.js的文件,您可以在平台文件夹中找到每个平台的文件。然后你还需要一些插件特定的文件。您可以通过构建并从那里提取它们来找到这些。对于android,路径如下APK/assets/www/plugins。只需复制服务器上的内容即可。

NOTE: you can also find the plugin specific files in the platform folder, but they are incomplete as they're missing cordova.define("... at the beginning. This leads to requiredand modulebeing undefined, so just do a build and get them from there.

注意:您还可以在平台文件夹中找到特定于插件的文件,但它们不完整,因为它们缺少 cordova.define("... 开头。这会导致必需模块未定义,因此只需进行构建并从那里得到它们。

回答by Guy L.

Simplest working solution which allows to load local file from a remote https page without mixed content errors:

最简单的工作解决方案,允许从远程 https 页面加载本地文件而不会出现混合内容错误:

For android: Disable mixed content policy using: https://developer.android.com/reference/android/webkit/WebSettings.html#MIXED_CONTENT_ALWAYS_ALLOW)

对于 android:禁用混合内容策略使用:https: //developer.android.com/reference/android/webkit/WebSettings.html#MIXED_CONTENT_ALWAYS_ALLOW

For ios: I submitted a PR to the file plugin which solves the mixed content problem on ios: apache/cordova-plugin-file#296 The fixed version is available at: https://github.com/guylando/cordova-plugin-fileIf you load a remote site https://example.comon the webview then it allows to access local files using the url: https://example.com/cdvfile/bundle/www/cordova.jsinstead of cdvfile://localhost/bundle/www/cordova.js And by this solves the mixed content problems

对于 ios:我向文件插件提交了 PR,该插件解决了 ios 上的混合内容问题:apache/cordova-plugin-file#296 固定版本位于:https: //github.com/guylando/cordova-plugin-文件如果您在 webview 上加载远程站点https://example.com则它允许使用 url 访问本地文件:https://example.com/cdvfile/bundle/www/cordova.js而不是 cdvfile:/ /localhost/bundle/www/cordova.js 从而解决了混合内容问题

回答by Ali Naci Erdem

I have worked to make it work for a very long time for phoneGap quick-debugging but could not find a way to make the API working without having the cordova.js together with the app (not on a remote location).

我已经努力让它在很长一段时间内用于 phoneGap 快速调试,但无法找到一种方法来使 API 在没有cordova.js 与应用程序(不在远程位置)一起工作的情况下工作。

I don't know exactly why this does not work. If you know the internal workings I'm looking forward to hearing it...

我不知道为什么这不起作用。如果你知道内部运作,我很期待听到它......

The last thing I've tried was to put a 100% by 100% iframe in the main html and load the local cordova.js in the same document. Then I was able to use the API but there were some scaling issues on iOS, which is another question...

我尝试的最后一件事是在主 html 中放置 100% x 100% iframe 并在同一文档中加载本地 cordova.js。然后我可以使用 API,但在 iOS 上存在一些扩展问题,这是另一个问题......

I do not remember the exact way I've implemented and structered this, but I'll edit if I can find it.

我不记得我实现和构建它的确切方式,但如果我能找到它,我会进行编辑。

回答by Rivera

It is a Cordova/PhoneGap imposed limitation here:

这是一个科尔多瓦/ PhoneGap的规定限制,在这里

    if (startFilePath == nil) {
        loadErr = [NSString stringWithFormat:@"ERROR: Start Page at '%@/%@' was not found.", self.wwwFolderName, self.startPage];
        NSLog(@"%@", loadErr);
        self.loadFromString = YES;
        appURL = nil;
    }

I have disabled this check in the past to let Cordova work with non-local file addresses.

我过去禁用了此检查,以便让 Cordova 使用非本地文件地址。