index.html 之外的访问 Cordova navigator.camera 插件未定义

Access Cordova navigator.camera plugin outside of index.html is undefined

似乎找不到对此的解释。我目前使用的是 Visual Studio 2015 RC。安装了相机插件并使用 Cordova 示例作为基础。但是,问题是,如果此代码在 index.html 页面之外,我将无法访问该插件。

我试过在第二页上引用 Cordova.js,但没有用。如何在 index.html 之外访问相机插件?这是我在 Cordova 示例中使用的代码:

索引页:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>CordovaApp</title>

    <!-- CordovaApp references -->
    <link href="css/index.css" rel="stylesheet" />
    <script src="scripts/jquery/jquery-2.1.4.min.js"></script>
    <script src="scripts/jquery.mobile-1.4.5/jquery.mobile-1.4.5.min.js"></script>
    <script>
        $(document).on('pagecreate', function () {
            $("#submitLogin").on("click", function () {
                MoveToPage("/test.html");
            });
            function MoveToPage(page) {
                var dirPath = dirname(location.href);
                fullPath = dirPath + page;
                window.location.href = fullPath;

                function dirname(path) {
                    return path.replace(/\/g, '/').replace(/\/[^\/]*$/, '');
                }
            }
        });

        //***For the sake of having it on two pages
        var pictureSource;
        var destinationType;

        document.addEventListener("deviceready", onDeviceReady, false);

        function onDeviceReady() {
            pictureSource = navigator.camera.PictureSourceType;
            destinationType = navigator.camera.DestinationType;
        }

        function onPhotoDataSuccess(imageData) {
            var smallImage = document.getElementById('smallImage');
            smallImage.style.display = 'block';
            smallImage.src = "data:image/jpeg;base64," + imageData;
        }
        function onPhotoURISuccess(imageURI) {
            var largeImage = document.getElementById('largeImage');
            largeImage.style.display = 'block';
            largeImage.src = imageURI;
        }
        function capturePhoto() {
            navigator.camera.getPicture(onPhotoDataSuccess, onFail, {
                quality: 50,
                destinationType: destinationType.DATA_URL
            });
        }
        function capturePhotoEdit() {
            navigator.camera.getPicture(onPhotoDataSuccess, onFail, {
                quality: 20, allowEdit: true,
                destinationType: destinationType.DATA_URL
            });
        }
        function getPhoto(source) {
            navigator.camera.getPicture(onPhotoURISuccess, onFail, {
                quality: 50,
                destinationType: destinationType.FILE_URI,
                sourceType: source
            });
        }
        function onFail(message) {
            alert('Failed because: ' + message);
        }
    </script>
</head>
<body>
    <button style="color:white; background-color:dodgerblue;" id="submitLogin">Log In</button>

    <!-- Cordova reference, this is added to your app when it's built. -->
    <script src="cordova.js"></script>
    <script src="scripts/platformOverrides.js"></script>

    <script src="scripts/index.js"></script>
</body>
</html>

第二页:

<!DOCTYPE html>
<html>
  <head>
    <title>Capture Photo</title>

    <script type="text/javascript" charset="utf-8" src="cordova.js"></script>
    <script type="text/javascript" charset="utf-8">

    var pictureSource;   // picture source
    var destinationType; // sets the format of returned value

    // Wait for device API libraries to load
    //
    document.addEventListener("deviceready",onDeviceReady,false);

    // device APIs are available
    //
    function onDeviceReady() {
        pictureSource=navigator.camera.PictureSourceType;
        destinationType=navigator.camera.DestinationType;
    }

    // Called when a photo is successfully retrieved
    //
    function onPhotoDataSuccess(imageData) {
      // Uncomment to view the base64-encoded image data
      // console.log(imageData);

      // Get image handle
      //
      var smallImage = document.getElementById('smallImage');

      // Unhide image elements
      //
      smallImage.style.display = 'block';

      // Show the captured photo
      // The in-line CSS rules are used to resize the image
      //
      smallImage.src = "data:image/jpeg;base64," + imageData;
    }

    // Called when a photo is successfully retrieved
    //
    function onPhotoURISuccess(imageURI) {
      // Uncomment to view the image file URI
      // console.log(imageURI);

      // Get image handle
      //
      var largeImage = document.getElementById('largeImage');

      // Unhide image elements
      //
      largeImage.style.display = 'block';

      // Show the captured photo
      // The in-line CSS rules are used to resize the image
      //
      largeImage.src = imageURI;
    }

    // A button will call this function
    //
    function capturePhoto() {
      // Take picture using device camera and retrieve image as base64-encoded string
      navigator.camera.getPicture(onPhotoDataSuccess, onFail, { quality: 50,
        destinationType: destinationType.DATA_URL });
    }

    // A button will call this function
    //
    function capturePhotoEdit() {
      // Take picture using device camera, allow edit, and retrieve image as base64-encoded string
      navigator.camera.getPicture(onPhotoDataSuccess, onFail, { quality: 20, allowEdit: true,
        destinationType: destinationType.DATA_URL });
    }

    // A button will call this function
    //
    function getPhoto(source) {
      // Retrieve image file location from specified source
      navigator.camera.getPicture(onPhotoURISuccess, onFail, { quality: 50,
        destinationType: destinationType.FILE_URI,
        sourceType: source });
    }

    // Called if something bad happens.
    //
    function onFail(message) {
      alert('Failed because: ' + message);
    }

    </script>
  </head>
  <body>
    <button onclick="capturePhoto();">Capture Photo</button> <br>
    <button onclick="capturePhotoEdit();">Capture Editable Photo</button> <br>
    <button onclick="getPhoto(pictureSource.PHOTOLIBRARY);">From Photo Library</button><br>
    <button onclick="getPhoto(pictureSource.SAVEDPHOTOALBUM);">From Photo Album</button><br>
    <img style="display:none;width:60px;height:60px;" id="smallImage" src="" />
    <img style="display:none;" id="largeImage" src="" />
  </body>
</html>

编辑:我发现我在索引页上创建的按钮使用:

window.location = path;

当我将此按钮更改为锚标记时,索引页面中的 javascript 保持加载状态,我可以在另一个页面上访问相机。然而,这对我来说仍然是个问题,因为我希望能够在 he/she 能够访问下一页和相机之前使用索引页上的 onclick 事件来验证我的用户。这也意味着我将不得不在我不想做的第一页上加载我所有的 javascript 。反正有这个吗?

编辑:可能有用的额外信息。我使用 Visual Studio 2015 RC 安装了插件。创建一个空白的 Cordova 应用程序并通过双击 config.xml > Plugins > Camera > Add 安装插件。我的 config.xml 看起来像这样:

<?xml version="1.0" encoding="utf-8"?>
<widget xmlns:cdv="http://cordova.apache.org/ns/1.0" xmlns:vs="http://schemas.microsoft.com/appx/2014/htmlapps" id="io.cordova.myappc768b8113d304787b0649513e48ca2c4" version="1.0.0" xmlns="http://www.w3.org/ns/widgets" defaultlocale="en-US">
  <name>CordovaApp2</name>
  <description>A blank project that uses Apache Cordova to help you build an app that targets multiple mobile platforms: Android, iOS, Windows, and Windows Phone.</description>
  <author href="http://cordova.io" email="dev@cordova.apache.org">Apache Cordova Team </author>
  <content src="index.html" />
  <access origin="*" />
  <vs:features />
  <preference name="SplashScreen" value="screen" />
  <preference name="windows-target-version" value="8.1" />
  <preference name="windows-phone-target-version" value="8.1" />
  <platform name="android">
    <icon src="res/icons/android/icon-36-ldpi.png" density="ldpi" />
    <icon src="res/icons/android/icon-48-mdpi.png" density="mdpi" />
    <icon src="res/icons/android/icon-72-hdpi.png" density="hdpi" />
    <icon src="res/icons/android/icon-96-xhdpi.png" density="xhdpi" />
  </platform>
  <platform name="ios">
    <!-- iOS 8.0+ -->
    <!-- iPhone 6 Plus  -->
    <icon src="res/icons/ios/icon-60-3x.png" width="180" height="180" />
    <!-- iOS 7.0+ -->
    <!-- iPhone / iPod Touch  -->
    <icon src="res/icons/ios/icon-60.png" width="60" height="60" />
    <icon src="res/icons/ios/icon-60-2x.png" width="120" height="120" />
    <!-- iPad -->
    <icon src="res/icons/ios/icon-76.png" width="76" height="76" />
    <icon src="res/icons/ios/icon-76-2x.png" width="152" height="152" />
    <!-- iOS 6.1 -->
    <!-- Spotlight Icon -->
    <icon src="res/icons/ios/icon-40.png" width="40" height="40" />
    <icon src="res/icons/ios/icon-40-2x.png" width="80" height="80" />
    <!-- iPhone / iPod Touch -->
    <icon src="res/icons/ios/icon-57.png" width="57" height="57" />
    <icon src="res/icons/ios/icon-57-2x.png" width="114" height="114" />
    <!-- iPad -->
    <icon src="res/icons/ios/icon-72.png" width="72" height="72" />
    <icon src="res/icons/ios/icon-72-2x.png" width="144" height="144" />
    <!-- iPhone Spotlight and Settings Icon -->
    <icon src="res/icons/ios/icon-small.png" width="29" height="29" />
    <icon src="res/icons/ios/icon-small-2x.png" width="58" height="58" />
    <!-- iPad Spotlight and Settings Icon -->
    <icon src="res/icons/ios/icon-50.png" width="50" height="50" />
    <icon src="res/icons/ios/icon-50-2x.png" width="100" height="100" />
  </platform>
  <platform name="windows">
    <icon src="res/icons/windows/Square150x150Logo.scale-100.png" width="150" height="150" />
    <icon src="res/icons/windows/Square150x150Logo.scale-240.png" width="360" height="360" />
    <icon src="res/icons/windows/Square30x30Logo.scale-100.png" width="30" height="30" />
    <icon src="res/icons/windows/Square310x310Logo.scale-100.png" width="" height="" />
    <icon src="res/icons/windows/Square44x44Logo.scale-240.png" width="106" height="106" />
    <icon src="res/icons/windows/Square70x70Logo.scale-100.png" width="70" height="70" />
    <icon src="res/icons/windows/Square71x71Logo.scale-240.png" width="170" height="170" />
    <icon src="res/icons/windows/StoreLogo.scale-100.png" width="50" height="50" />
    <icon src="res/icons/windows/StoreLogo.scale-240.png" width="120" height="120" />
    <icon src="res/icons/windows/Wide310x150Logo.scale-100.png" width="310" height="150" />
    <icon src="res/icons/windows/Wide310x150Logo.scale-240.png" width="744" height="360" />
  </platform>
  <platform name="wp8">
    <icon src="res/icons/wp8/ApplicationIcon.png" width="62" height="62" />
    <icon src="res/icons/wp8/Background.png" width="173" height="173" />
  </platform>
  <platform name="android">
    <splash src="res/screens/android/screen-hdpi-landscape.png" density="land-hdpi" />
    <splash src="res/screens/android/screen-ldpi-landscape.png" density="land-ldpi" />
    <splash src="res/screens/android/screen-mdpi-landscape.png" density="land-mdpi" />
    <splash src="res/screens/android/screen-xhdpi-landscape.png" density="land-xhdpi" />
    <splash src="res/screens/android/screen-hdpi-portrait.png" density="port-hdpi" />
    <splash src="res/screens/android/screen-ldpi-portrait.png" density="port-ldpi" />
    <splash src="res/screens/android/screen-mdpi-portrait.png" density="port-mdpi" />
    <splash src="res/screens/android/screen-xhdpi-portrait.png" density="port-xhdpi" />
  </platform>
  <platform name="ios">
    <splash src="res/screens/ios/screen-iphone-portrait.png" width="320" height="480" />
    <splash src="res/screens/ios/screen-iphone-portrait-2x.png" width="640" height="960" />
    <splash src="res/screens/ios/screen-ipad-portrait.png" width="768" height="1024" />
    <splash src="res/screens/ios/screen-ipad-portrait-2x.png" width="1536" height="2048" />
    <splash src="res/screens/ios/screen-ipad-landscape.png" width="1024" height="768" />
    <splash src="res/screens/ios/screen-ipad-landscape-2x.png" width="2048" height="1536" />
    <splash src="res/screens/ios/screen-iphone-568h-2x.png" width="640" height="1136" />
    <splash src="res/screens/ios/screen-iphone-portrait-667h.png" width="750" height="1334" />
    <splash src="res/screens/ios/screen-iphone-portrait-736h.png" width="1242" height="2208" />
    <splash src="res/screens/ios/screen-iphone-landscape-736h.png" width="2208" height="1242" />
  </platform>
  <platform name="windows">
    <splash src="res/screens/windows/SplashScreen.scale-100.png" width="620" height="300" />
    <splash src="res/screens/windows/SplashScreen.scale-240.png" width="1152" height="1920" />
    <splash src="res/screens/windows/SplashScreenPhone.scale-240.png" width="1152" height="1920" />
  </platform>
  <platform name="wp8">
    <splash src="res/screens/wp8/SplashScreenImage.jpg" width="480" height="800" />
  </platform>
  <vs:plugin name="org.apache.cordova.camera" version="0.3.6" />
  <feature name="Camera">
    <param name="android-package" value="org.apache.cordova.CameraLauncher" />
  </feature>
</widget>

当使用锚点或 window.location.href 导航到第二页时,这不会在使用 Cordova 4.3.0 和 VS 2015 RC 的简单项目上重现。如果您确实要导航到另一个页面,则需要确保在第二个页面上添加 cordova.js 脚本引用。请参阅下面的说明此工作原理的页面。

发生的情况很可能是以下情况之一:

  1. "Single page app" JavaScript 框架通常会向锚点等元素添加事件侦听器,这样当您单击它们时,它们会在幕后加载页面并使用过渡效果淡入淡出。但是,它所做的实际上是让您从 "window" 的角度保持在同一页面上。 DOM 未卸载,因此您不需要重新加载所有 JS 代码。好的框架也会更新导航历史,这样后退按钮之类的东西就可以工作了。我相信 jQuery 移动是这些框架之一。像这样的 SPA 框架通常提供某种 API 来在后台从代码转换。但是,显式调用 window.location 将绕过您的 JavaScript 框架并导致它转储 DOM 的全部内容,您将不得不重新加载所有 JavaScript包括 cordova.js。 (与从 http://www.microsoft.com to http://www.bing.com 开始没有什么不同。这是一项关键的安全功能。)要解决此问题,您不应使用 window.location 进行导航,而应使用 SPA 框架的导航 APIs进行页面转换。
  2. 如果您在第二页上引用了 cordova.js 以及所有 JavaScript 代码,您可能在代码的前面遇到了导致负载的 JavaScript 异常cordova.js 不会发生,因为执行因异常而停止。
  3. 我们刚刚在将某些文件签入源代码管理时发现了一个问题。我们最近发现,签入插件文件夹中的 android.json、windows.json、wp8.json 或 remote_ios.json 文件可能会导致构建成功但插件不成功的奇怪行为功能。存在问题的唯一迹象是您将在输出 window 中看到异常。参见

看到这个正常工作。将这些文件添加到一个空白项目中,然后通过配置设计器添加相机插件,以从第二页查看工作情况。相机将打开,您可以拍照。单击锚点或按钮将移动到第二页,然后执行相同的操作。

www/index.html:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>Second Page Test</title>   
    <link href="css/index.css" rel="stylesheet" />
</head>
<body>
    <a href="page2.html">Click to go to page 2 via anchor!</a>
    <button id="gotopage2">Click to go to page 2 via window.location.href</button>
    <!-- Cordova reference, this is added to your app when it's built. -->
    <script src="cordova.js"></script>
    <script src="scripts/platformOverrides.js"></script>
    <script src="scripts/index.js"></script>
    <img id="myImage" src="#"/>
</body>
</html>

www/page2.html:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>Second Page Test</title>
    <link href="css/index.css" rel="stylesheet" />
</head>
<body>
    <!-- Cordova reference, this is added to your app when it's built. -->
    <script src="cordova.js"></script>
    <script src="scripts/platformOverrides.js"></script>
    <script src="scripts/index.js"></script>
    <img id="myImage" src="#" />
</body>
</html>

www/scripts/index.js:

(function () {
    "use strict";

    document.addEventListener( 'deviceready', onDeviceReady.bind( this ), false );

    function onDeviceReady() {
        // Handle the Cordova pause and resume events
        document.addEventListener( 'pause', onPause.bind( this ), false );
        document.addEventListener( 'resume', onResume.bind( this ), false );

        var page2button = document.getElementById("gotopage2")
        if (page2button) {
            page2button.addEventListener("click", function () {
                window.location.href = "page2.html";
            });
        }
        navigator.camera.getPicture(onSuccess, onFail, {
            quality: 50,
            destinationType: Camera.DestinationType.DATA_URL
        });

        function onSuccess(imageData) {
            var image = document.getElementById('myImage');
            image.src = "data:image/jpeg;base64," + imageData;
        }

        function onFail(message) {
            alert('Failed because: ' + message);
        }
    };

    function onPause() {
        // TODO: This application has been suspended. Save application state here.
    };

    function onResume() {
        // TODO: This application has been reactivated. Restore application state here.
    };
} )();