【问题标题】:Cordova + Angularjs + Device ReadyCordova + Angularjs + 设备就绪
【发布时间】:2014-02-28 15:14:27
【问题描述】:

我正在使用 Cordova 和 AngularJS 开发一个移动应用程序。如何在 Cordova 设备准备好之前限制 AngluarJS 的引导。基本上我不想在设备准备好之前使用任何 AngularJS 控制器。

【问题讨论】:

标签: angularjs cordova angularjs-service


【解决方案1】:

手动引导您的 Angular 应用:

从您的 HTML 代码中删除您的 ng-app 属性,因此 Angular 不会自行启动。

在 JavaScript 代码中添加类似这样的内容:

document.addEventListener("deviceready", function() {
    // retrieve the DOM element that had the ng-app attribute
    var domElement = document.getElementById(...) / document.querySelector(...);
    angular.bootstrap(domElement, ["angularAppName"]);
}, false);

bootstrapping 应用程序的 Angular 文档。

【讨论】:

  • 设备就绪事件是否总是在文档就绪后触发?如果没有,有时这将不起作用
  • 当应用程序在浏览器中运行时,如果没有 Cordova,这将不起作用。我下面的解决方案解决了这个问题。
  • 请参阅下面我的回答,了解@olanod 的担忧。 @michaeloryl @wade-anderson 回答的window.ionic.Platform.ready() 怎么样?
【解决方案2】:

我正在使用以下解决方案,它允许 AngularJS 在与 Cordova 一起运行时以及在直接在浏览器中运行时被引导,这是我的大部分开发工作发生的地方。您必须从主 index.html 页面中删除 ng-app 指令,因为这是手动引导正在取代的内容。

更新:我已经切换到以下方法,我认为它更清洁。它适用于 Ionic 以及 vanilla Cordova/PhoneGap。它应该是 JavaScript 的最后一点运行 - 可能在 /body 标记之前的 script 标记内。

  angular.element(document).ready(function () {
    if (window.cordova) {
      console.log("Running in Cordova, will bootstrap AngularJS once 'deviceready' event fires.");
      document.addEventListener('deviceready', function () {
        console.log("Deviceready event has fired, bootstrapping AngularJS.");
        angular.bootstrap(document.body, ['app']);
      }, false);
    } else {
      console.log("Running in browser, bootstrapping AngularJS now.");
      angular.bootstrap(document.body, ['app']);
    }
  });

这是我使用的旧解决方案:

// This is a function that bootstraps AngularJS, which is called from later code
function bootstrapAngular() {
    console.log("Bootstrapping AngularJS");
    // This assumes your app is named "app" and is on the body tag: <body ng-app="app">
    // Change the selector from "body" to whatever you need
    var domElement = document.querySelector('body');
    // Change the application name from "app" if needed
    angular.bootstrap(domElement, ['app']);
}

// This is my preferred Cordova detection method, as it doesn't require updating.
if (document.URL.indexOf( 'http://' ) === -1 
        && document.URL.indexOf( 'https://' ) === -1) {
    console.log("URL: Running in Cordova/PhoneGap");
    document.addEventListener("deviceready", bootstrapAngular, false);
} else {
    console.log("URL: Running in browser");
    bootstrapAngular();
}

如果您在使用 http/https 检测方法时遇到问题,可能是因为从 Web 将 Cordova 应用程序加载到手机中,您可以改用以下方法:

function bootstrapAngular() {
    console.log("Bootstrapping AngularJS");
    // This assumes your app is named "app" and is on the body tag: <body ng-app="app">
    // Change the selector from "body" to whatever you need
    var domElement = document.querySelector('body');
    // Change the application name from "app" if needed
    angular.bootstrap(domElement, ['app']);
}

// This method of user agent detection also works, though it means you might have to maintain this UA list
if (navigator.userAgent.match(/(iOS|iPhone|iPod|iPad|Android|BlackBerry)/)) {
    console.log("UA: Running in Cordova/PhoneGap");
    document.addEventListener("deviceready", bootstrapAngular, false);
} else {
    console.log("UA: Running in browser");
    bootstrapAngular();
}

请注意,您仍然需要与第一个示例相同的 bootstrapAngular 函数。

为什么要使用 Cordova/PhoneGap/Ionic 手动引导 AngularJS?

有些人一开始可能不知道您为什么要这样做。问题是您可能拥有依赖于 Cordova/PhoneGap/Ionic 插件的 AngularJS 代码,而这些插件要等到 AngularJS 启动后才能准备好,因为 Cordova 在设备上启动和运行所需的时间比普通的旧 Javascript 代码要长对于 AngularJS 来说。

所以在这些情况下,我们必须等到 Cordova/PhoneGap/Ionic 准备好后才能启动(引导)AngularJS,以便 Angular 拥有运行所需的一切。

例如,假设您正在使用 NG-Persist Angular 模块,它利用本地存储在浏览器上保存数据,iOS Keychain plugin(在 iOS 上运行)和 cordova-plugin-file(在 Android 上运行)。如果您的 Angular 应用程序尝试立即加载/保存某些内容,NG-Persist 对 window.device.platform(来自 device plugin)的检查将失败,因为移动代码尚未完成启动,您将得到只不过是一个白页,而不是你漂亮的应用程序。

【讨论】:

  • 为了能够在浏览器中进行测试,我通常会创建一个包含一些代码的虚假 cordova.js 文件,例如自动立即调用任何“deviceready”注册事件。
  • @user276648 你能分享你的假cordova.js(例如作为github gist)吗?
  • 如果我这样做,我会得到“未捕获的错误:[$injector:modulerr] 无法实例化模块应用程序,原因是:错误:[$injector:nomod] 模块‘app’不可用!你要么拼错了模块名称,要么忘记加载它。如果注册模块,请确保将依赖项指定为第二个参数。”我能做什么?
  • @KenVernaillen 我的猜测是您的主应用程序模块不像我的示例中那样称为app。查看angular.bootstrap(document.body, ['app']); 这两行并将其更改为您应用程序中的主模块的名称。如果它对您有用,请不要忘记投票......
  • @MichaelOryl Sir 这是否意味着我不再需要在我的个人插件调用中准备好设备?
【解决方案3】:

如果您使用Ionic,此解决方案适用于浏览器和设备。在此 thread 上感谢 romgar

window.ionic.Platform.ready(function() {
    angular.bootstrap(document, ['<your_main_app']);
});

仍然需要从 DOM 元素中删除 ng-app。

【讨论】:

  • 这太棒了
  • 这仅在您使用 Ionic 时有效(在撰写问题时不存在)。仍然有开发人员在没有 Ionic 的情况下使用 Cordova 和 Angular。
  • @TheHippo 谢谢先生。我错过了。我已经编辑了我的答案,以包括您使用 Ionic 的规定。
  • 你能举一个完整的例子吗?我无法让它工作。这段代码在 angular.module.run、$ionicPlatform.ready 内部还是外部?
  • @CarlosGoce 代码 sn-p 不应该在 Angular 中运行。它在您的 HTML 页面底部以纯 Javascript 执行。如果您的 HTML 中确实有 ng-app 属性,请记住不要删除它 - 它的功能被上面的 sn-p 引导 Angular 所取代
【解决方案4】:

当我使用时,这个解决方案变得更加健壮:

angular.element(document).ready(function () {
  var domElement = document.getElementById('appElement');
  angular.bootstrap(domElement, ["angularAppName"]);
});

更新

我的建议是将上述内容放在适当的 deviceready 函数中,例如:

document.addEventListener("deviceready", function() {
    angular.element(document).ready(function () {
      var domElement = document.getElementById('appElement');
      angular.bootstrap(domElement, ["angularAppName"]);
    });
}, false);

【讨论】:

  • documentReady != deviceready 如果您在代码的早期使用任何特定于 Cordova 的函数,则这些函数可能还没有准备好。
  • 这应该在 deviceready 处理程序中,并取自引导文档。
  • 另外,如果你在 HTML 元素之后包含你的 JavaScript,你不需要等到 DOM 完全加载。
  • 我不明白反对意见。我的建议来自引导文档,完整的代码是(对我来说很好):document.addEventListener("deviceready", function() { angular.element(document).ready(function () { // retrieve the DOM element that had the ng-app attribute var domElement = document.getElementById('appElement'); angular.bootstrap(domElement, ["angularAppName"]); }); }, false);
  • 您能否详细说明为什么您说这更健壮? @TheHippo 的解决方案是否有时会为您失败?
【解决方案5】:

关于使用 TheHippo 的解决方案:

document.addEventListener("deviceready", function() {
    // retrieve the DOM element that had the ng-app attribute
    var domElement = document.getElementById(...) / document.querySelector(...);
    angular.bootstrap(domElement, ["angularAppName"]);
}, false);

它在浏览器中不起作用,因为“cordova.js”由 Cordova 或 Phonegap 构建过程解析,并且在您的本地主机或模拟测试环境中不可用。

因此永远不会触发“deviceready”事件。您可以简单地在浏览器控制台中手动触发它。

var customDeviceReadyEvent = new Event('deviceready');
document.dispatchEvent(customDeviceReadyEvent);

还要确保在设置所有 Angular 模块/控制器/工厂/指令等后触发 Angular 的引导程序。

【讨论】:

    【解决方案6】:

    在大多数情况下,您可能不需要在 deviceready 之前阻止加载您的 Angular 应用程序(请注意,如果您有很多插件,deviceready 可能需要几秒钟才能触发)。

    相反,您可以使用类似这个库 (https://github.com/arnesson/angular-cordova) 的东西,它通过自动缓冲调用为您解决 deviceready 问题,然后在 deviceready 被触发后执行它们。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-07-01
      • 2015-11-27
      • 1970-01-01
      • 1970-01-01
      • 2011-12-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多