Кордова 2.2.0 на iOS - RequireJS не будет правильно загружать Кордову

В настоящее время я разрабатываю webapp, используя Cordova (Phonegap), Backbone и JQtouch. Помимо прочего, мне нужно добавить события в календарь пользователя.

Все отлично работает на Android. Я все еще использую Cordova 2.0.0. (Я не обновлялся до последней версии). Прокрутка работает, навигация в порядке, и я могу добавлять события в свой календарь!

На iPhone это другое. Поскольку я хочу, чтобы мое приложение работало на iOS 6, я получил Кордову 2.2.0 на своем Mac. С тех пор я больше не могу добавлять события в календарь. Он работал (на iphone) с cordova 2.0.0, но не сейчас.

После исследования выяснилось, что cordova.exec() undefined.

Я много искал об этой проблеме, но, похоже, никто, кроме меня, не встретил эту проблему на данный момент.

Вот примеры кода, которые работают с Cordova 2.0.0, но не с Cordova 2.2.0:

calendar.js, плагин календаря для Кордовы. Я этого не писал. На Android я получаю сообщение "cordova.exec определено", а на iOS я получаю другой.

// Cordova Calendar Plugin
// Author: Felix Montanez 
// Created: 01-17-2012
// Contributors:
// Michael Brooks    

function calendarPlugin()
{
}

calendarPlugin.prototype.createEvent = function(title,location,notes,startDate,endDate)
{
    if('function' == typeof(cordova.exec)) {
        alert("cordova.exec is defined");
    } else {
        alert("cordova.exec is not defined");
    }
    cordova.exec(null,null,"calendarPlugin","createEvent", [title,location,notes,startDate,endDate]);
};

calendarPlugin.install = function()
{
    if(!window.plugins)
    {
        window.plugins = {};
    }    
    window.plugins.calendarPlugin = new calendarPlugin();
    return window.plugins.calendarPlugin;
};

cordova.addConstructor(calendarPlugin.install);

Код, вызывающий функцию createEvent (он работает, поскольку я получил предыдущее предупреждение)

if (confirm('Do you want to add this event in your calendar?')) 
{ 
    calendarPlugin.prototype.createEvent('<%= paramEvent_map %>', 'Geneva', 
        'Convocation', '<%= paramEvent_startDate %>', '<%= paramEvent_endDate %>'); 
}

Возможным источником этой проблемы может быть способ, которым я модернизировался от Cordova 2.0.0 до Cordova 2.2.0: я только что последовал за учебником "Обновление проектов Cordova 2.1.0 до версии 2.2.0". Должен ли я сделать "От 2.0.0 до 2.1.0", затем "Form 2.1.0 to 2.2.0"?

Я был бы признателен за любое предложение об этом, так как я действительно не хочу перезапускать мою установку телефонного разговора.

На Mac я работаю с Mountain Lion 10.8 и xCode 4.5, и я тестирую свое приложение на iOS 4 и 6. На ПК я работаю с Aptana studio 3 и Eclipse 3.7.1, и я тестирую Android 2.3.

--- EDIT: переустановите Cordova 2.1.0, затем обновите до 2.2.0 ---

Я просто удалил свой проект, удалил Кордову и переделал все "с нуля":

  • Я установил Кордову 2.1.0 с их сайта.
  • Я обновил xcode до 4.5.2 (как рекомендовано)
  • Я создал проект xcode, в котором я скопировал части своего кода.
  • Я выполнил их учебник для обновления с Кордовы 2.1.0 до Кордовы 2.2.0
  • Я установил "Архитектуры" в "armv7, armv7s" и "Build Active Architecture Only" на "Yes"
  • Я добавил фреймворки, необходимые для плагина календаря: EventKit и EventKitUI

Затем я скомпилировал и запустил проект на своем iPhone 3 (с iOS 6), а cordova.exec до сих пор не определен!

--- EDIT: объявите плагин моего календаря как модуль ---

Я добавил код для плагина календаря непосредственно в cordova-2.2.0.js(я в отчаянии).

Теперь в cordova-2.2.0.js у меня есть следующие строки: (Я получил их отсюда)

define("cordova/plugin/calendarplugin", function(require, exports, module) {
    var exec = require('cordova/exec');

    var calendarPlugin = function() {};

    calendarPlugin.prototype.createEvent = function(title,location,notes,startDate,endDate) {
         exec(null, null, 'calendarPlugin', 'createEvent', [title,location,notes,startDate,endDate]);
    }

    var myCalendarPlugin = new calendarPlugin();
    module.exports = myCalendarPlugin;
});

Поэтому я больше не использую cordova.exec(), но вместо этого:

var exec = require('cordova/exec');

Мой календарь "подключаемый" файл теперь содержит только следующую строку:

var mycalendarplugin = cordova.require("cordova/plugin/calendarplugin");

И вот как я использую свой новый "модуль":

window.mycalendarplugin.createEvent('<%= paramEvent_map %>', 'Geneva', 
'Convocation', '<%= paramEvent_startDate %>', '<%= paramEvent_endDate %>');

И, что удивительно, вызывается функция exec()!

Однако я получил следующее сообщение: " ОШИБКА: попытка вызвать cordova.exec() перед" deviceready ". Игнорирование.", которое должно появляться, когда "deviceReady" не запускается.

К сожалению, это событие НИКОГДА не срабатывает. Поэтому моя проблема сейчас немного отличается, но все еще остается.

--- EDIT: сравнение с Android ---

Я добавил несколько строк для прослушивания событий, как в Android, так и в iOS:

window.addEventListener('load', function () {
     alert("load triggered");
     document.addEventListener('deviceready', function () {
            alert("PhoneGap is now loaded!");
     }, false);
}, false);

В iOS я получаю сообщение "load triggered", но не "PhoneGap теперь загружен". После этого я все еще не могу использовать exec().

На Android я вообще не получаю сообщений. Но я могу использовать cordova.exec() без проблем.

--- РЕДАКТИРОВАТЬ: отменить проект с нуля ---

Вместо того, чтобы создавать свой проект с помощью cordova 2.1.0, а затем обновить до кордовы 2.2.0, я попытался создать образец проекта непосредственно с кордоной 2.2.0, а затем включить в него плагин календаря (оригинальная версия).

И он отлично работает! С небольшим количеством кода для iOS 6 (для которого требуется явная авторизация от пользователя), я могу добавлять события в свой календарь.

Однако, как только я добавлю остальную часть моего проекта (html, css, js файлы), я получаю ту же ошибку: cordova.exec - undefined.

Ответственный может быть RequireJS, который может загружать cordova-2.2.0.js другим способом. Он отлично работал с кордовой 2.0.0, но, похоже, не с 2.2.0.

Я попытаюсь посмотреть, могу ли я загружать кордову-2.2.0.js перед RequireJS и все еще использовать ее после загрузки кордовы.

Я буду держать вас в курсе:)

Ответ 1

Извините, что ответил на мой собственный вопрос.

Это было то, что я думал в своем последнем редактировании: RequireJS возится с Cordova 2.2.0!

До этого я использовал этот код для загрузки кордовы:

require.config({
  paths: {
    cordova: 'libs/cordova/cordova-2.2.0', ...

Перед любым из моих script, которые используют кордову, я писал:

define([
  'jquery',
  'cordova',
  ...
], function($) { ... }

В моем index.html у меня было:

<script data-main="js/main" src="js/libs/require/require-jquery.js"></script>

И он отлично справился с cordova 2.0.0! Но с кордовой 2.2.0, это просто НЕПРАВИЛЬНО.

Чтобы решить мою проблему:

Я избавился от всего о кордове в предыдущих строках.

  • Больше нет cordova в require.config.
  • Больше нет кордоны в определяющей части моих js-функций.

Вместо этого я добавил только одну строку в свой index.html:

<script type="text/javascript" src="libs/cordova/cordova-2.2.0.js"></script>
<script data-main="js/main" src="js/libs/require/require-jquery.js"></script>

И все работает отлично! Я могу снова позвонить cordova.exec()! (Протестировано на iOS 4, iOS 6 и на iPhone 5).

Честно говоря, я не очень хорошо понимаю, как все это работает. Я просто предполагаю, что кордову нужно загружать до всего остального (например, jquery), а RequireJS не подходит для этого (или я не знаю, как его использовать).

Это было ужасно. Я рад этому:)

В любом случае, я надеюсь, что это будет полезно для кого-то.

Ответ 2

В вашем объекте require.config вам необходимо экспортировать кордову с помощью атрибута shim:

require.config({
   baseUrl: 'js',
   paths: {
      cordova: '../lib/cordova/cordova-2.2.0'
   },
   shim: {
      cordova: {
         exports: 'cordova'
      }
   }
});

Лучше всего определить модуль для доступа к кордовому модулю exec:

/*global define */

define(['cordova'], function (cordova) {
   'use strict';

   return cordova.require('cordova/exec');
});

Создание настраиваемого плагина теперь легко:

/*global define */

define(['plugins/cordovaExec'], function (cordovaExec) {
   'use strict';

   return function showToast(callback, message) {
      cordovaExec(callback, function (error) {}, "Toaster", "show", [message]);
   };
});

Вы можете сделать это только в одном модуле:

/*global define */

define(['cordova'], function (cordova) {
   'use strict';

   var exec = cordova.require('cordova/exec');

   return function showToast(callback, message) {
      exec(callback, function (error) {}, "Toaster", "show", [message]);
   };
});

Надеюсь, что помогает:)