Статьи

Создание мобильных модулей Titanium с использованием CommonJS

В этой статье мы поговорим о том, как создавать свои собственные мобильные модули для Applelerator’s Titanium, используя только JavaScript и немного знаний CommonJS. Модуль, который мы создадим, будет предназначен для Picasa, службы изображений Google, и позволит нашим пользователям просматривать альбомы и фотографии из Picasa, не зная каких-либо подробностей о самом API Picasa. После того, как мы протестировали наш модуль, мы также проведем его упаковку для iOS и Android!


Зачем упаковывать в модуль вообще? Код, который мы создаем, в конце концов, JavaScript. Мы могли бы просто скопировать и вставить наши файлы кода в любой проект Appcelerator Titanium, чтобы использовать их. Однако есть ряд очень веских причин сделать это как модуль.

  • Ваши модули могут использоваться совместно и рассматриваться как компонент «черного ящика», как и любой другой собственный модуль.
  • Ваши модули скомпилированы, что означает, что вы можете защитить свой код, если вам нужно.
  • Модули просты в обслуживании и распространяются на ваши проекты, что позволяет вам более легко повторно использовать ваш код.

Теперь, когда у нас есть «почему», давайте перейдем к «как» и создадим наш модуль!


Самый простой способ создать новый проект мобильного модуля — это использовать Titanium Studio, поэтому мы и собираемся это сделать. Откройте Titanium Studio и в меню « Файл» выберите « Создать»> «Проект мобильного модуля» . Вам будет представлен экран, подобный показанному ниже. Я называю наш модуль » Picasa » и даю ему идентификатор модуля » com.boydlee.picasa «. Запишите, какой у вас идентификатор модуля, если вы решите использовать другой идентификатор. Это будет очень важно, когда мы создадим наши файлы JavaScript позже!

Создание нового проекта мобильного модуля в Titanium Studio

Вы, вероятно, заметите, что на этом этапе вы можете создать свой модуль только для iOS ИЛИ Android. Это связано с тем, что модули компилируются отдельно для каждой платформы. Я собираюсь выбрать и использовать iOS для нашего модуля прямо сейчас. Его гораздо быстрее собрать и протестировать, чем Android. Мы создадим наш модуль Android, используя тот же код в конце урока. Нажмите кнопку « Готово» , и Titanium Studio должен создать проект модуля и отобразить его на панели «Обозреватель приложений». Давайте начнем кодировать!


Первое, что нам нужно сделать, это создать файл ввода JavaScript для нашего модуля, который будет находиться в каталоге / assets . Он должен быть назван определенным образом, который должен быть: your.module.id.js . Поскольку я назвал свой модуль com.boydlee.picasa , файл JavaScript, который мне нужно создать, должен называться com.boydlee.picasa.js . Ваша панель обозревателя приложений должна выглядеть примерно так, как на фотографии.

Панель обозревателя приложений в Titanium Studio

Titanium автоматически ищет файл точки входа при загрузке вашего модуля, и этот файл точки входа должен иметь то же имя, что и идентификатор вашего модуля. Давайте начнем создавать наш модуль CommonJS, начиная с кода оболочки, который создаст нашу функцию Picasa, добавит к нему объект « Уровни доступа » для удобства с использованием прототипа , а затем экспортирует функцию через CommonJS.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
/*
* Our Picasa CommonJS Module
*/
function Picasa(){
   this._username = »;
   this._accessLevel = ‘public’;
};
 
Picasa.prototype.ACCESS_LEVELS = {
    PUBLIC: ‘public’,
    PRIVATE: ‘private’
};
 
//finally, export the module
//you MUST export it in this manner, not using methods.export = !
exports.Picasa = Picasa;

Теперь, когда наша базовая оболочка модуля готова, пришло время заполнить ее некоторыми функциями, используя прототип. Мы собираемся сделать этот модуль довольно простым, поэтому он будет преследовать только две основные цели: искать и возвращать список альбомов пользователя и возвращать список всех фотографий для альбома. Во-первых, давайте создадим несколько общедоступных методов получения и установки, чтобы мы могли установить имя пользователя и уровни доступа.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
/*
Getters and setters for our private functions
 */
Picasa.prototype.setUsername = function(value){
    this._username = value;
};
 
Picasa.prototype.getUsername = function(){
    return this._username;
};
 
Picasa.prototype.setAccessLevel = function(value){
    this._accessLevel = value;
};
 
Picasa.prototype.getAccessLevel = function(){
    return this._accessLevel;
};

Нам также понадобится функция, которая может выполнять HTTP-запросы. Вместо того, чтобы создавать несколько запросов для альбомов и фотографий для Picasa, мы можем создать одну функцию запроса, которую можно использовать повторно. Давайте сделаем это сейчас.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
/*
 * Our xhr function accepts a URL and 2 callback functions
 */
Picasa.prototype.xhr = function(url, success, error){
    var client = Ti.Network.createHTTPClient({
         // function called when the response data is available
         onload : function(e) {
             Ti.API.info(«Received JSON Text: » + this.responseText);
             var json = JSON.parse(this.responseText);
             success(json);
         },
         // function called when an error occurs, including a timeout
         onerror : function(e) {
             Ti.API.debug(e.error);
             error(e.error);
         },
         timeout : 5000 //in milliseconds
     });
      
     client.open(«GET», url);
     client.send();
};

Давайте расширим нашу функцию Picasa некоторыми функциями, которые будут принимать имя пользователя и уровень доступа и возвращать действительные URL-адреса для службы фотографий Picasa. Мы будем использовать эти URL позже, когда будем создавать наши запросы HttpRequest.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function Picasa(){
    this._username = »;
    this._accessLevel = ‘public’;
    var _this = this;
     
    this.albumnsEndpoint = function(username, accessLevel){
       username = (username === undefined) ?
       accessLevel = (accessLevel === undefined) ?
       return ‘https://picasaweb.google.com/data/feed/api/user/’ + username + ‘?kind=album&access=’ + accessLevel + ‘&alt=json’;
    };
     
    this.albumPhotosEndpoint = function(albumId, username, accessLevel){
       if(albumId === undefined){
           Ti.API.error(‘This method requires an album ID!’);
           return;
       }
        
       username = (username === undefined) ?
       accessLevel = (accessLevel === undefined) ?
       return ‘https://picasaweb.google.com/data/entry/api/user/’ + username + ‘/albumid/’ + albumId + ‘?alt=json’;
    };
     
};

Теперь, когда базовая структура нашего модуля существует, мы можем начать сборку с использованием API Picasa и добавить реальные функциональные возможности и полезность нашему модулю. Первое, что мы сделаем, это создадим функцию, которая позволит нашему пользователю получить список своих альбомов Picasa. Информация JSON, которую Picasa возвращает для этого вызова, чрезвычайно сложна, поэтому мы также упростим ее до красивого аккуратного массива объектов, которые вы можете легко понять с первого взгляда. Идите дальше и создайте следующую функцию в вашем модуле CommonJS.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/*
 * This function will fetch the albums url, parse the JSON response and simplify before
 * passing it to our callback function
 */
Picasa.prototype.getAlbums = function(callback){
    if(this._username !== undefined){
        var albumsUrl = this.albumnsEndpoint(this._username);
         
        this.xhr(
            albumsUrl,
            function(response){
               var albums = [];
               for(var i = 0; i < response.feed.entry.length; i++){
                   var album = {
                        title: response.feed.entry[i].title.$t,
                        thumbnail: response.feed.entry[i].media$group.media$thumbnail[0].url,
                        thumbnailWidth: response.feed.entry[i].media$group.media$thumbnail[0].width,
                        url: response.feed.entry[i].link[0].href
                   };
                   albums.push(album);
               }
                
               callback(albums);
            },
            function(failure){
               callback(failure);
        });
         
    };
};

Теперь, когда мы можем получить доступ к данным альбома, нам нужно использовать конечные точки фотографий Picasa для получения списка фотографий для определенного альбома. Это можно сделать двумя способами. Вы можете использовать идентификатор альбома и создать конечную точку URL-адреса фотографии или просто использовать URL-адрес, возвращаемый обратно в HTTP-запросе альбома. Мы создадим обе функции просто для удобства и третью функцию с именем createPhotosArray , которая примет объект ответа JSON и вернет обратно упрощенный массив изображений. В вашем модуле CommonJS создайте следующие функции.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
/*
 * Takes in a photos URL response JSON object and just returns
 * the important information (an array photo objects)
 */
Picasa.prototype.createPhotosArray = function(response){
    var photos = [];
     
    for(var i = 0; i < response.feed.entry.length; i++){
        var photo = {
           title: response.feed.entry[i].title.$t,
           url: response.feed.entry[i].content.src
        };
         
        photos.push(photo);
    }
     
    return photos;
};
 
/*
 *
 */
Picasa.prototype.getPhotosByUrl = function(url, callback){
     var _this = this;
     
    this.xhr(
       url,
       function(response){
          callback(_this.createPhotosArray(response));
       },
       function(failure){
          callback(failure);
    });
};
 
 
/*
 *
 */
Picasa.prototype.getPhotosByAlbumId = function(albumId, callback){
    var _this = this;
     
    if(this._username !== undefined && albumId !== undefined){
        var photosUrl = this.albumPhotosEndpoint(albumId, this._username);
     
        this.xhr(
            photosUrl,
            function(response){
                callback(_this.createPhotosArray(response));
            },
            function(failure){
               callback(failure);
        });
    }
};

Вот и все, что касается нашего модуля CommonJS! Теперь мы можем установить наше имя пользователя и уровни доступа с помощью функций общедоступных свойств, получить список альбомов и использовать эту информацию, чтобы затем получить соответствующий список фотографий для каждого идентификатора альбома / URL-адреса альбома. В следующем разделе, где мы поговорим об упаковке нашего модуля для использования в реальном приложении Titanium Mobile!


Упаковка вашего модуля не может быть проще при использовании Titanium Studio. Сначала щелкните значок « Пакет » на панели «Обозреватель приложений». Значок пакета выглядит как закрытое поле. Затем нажмите на опцию подменю « Пакет — iOS-модуль ». Появится новое всплывающее окно, похожее на приведенное ниже, с тремя различными вариантами упаковки.

  • Titanium SDK — это упакует ваш модуль и установит его непосредственно в каталог «Modules» вашего Titanium SDK. На Mac это находится в папке ~ / Application Support / Titanium .
  • Мобильный проект — это упакует ваш модуль и установит его непосредственно в приложение, которое в настоящее время находится на панели Project Explorer. Если вы хотите протестировать модуль, над которым вы работаете, это, как правило, самый простой способ.
  • Расположение — это упакует ваш модуль и сохранит полученный ZIP-файл в указанную вами папку. Это лучший способ, если вы хотите поделиться своим модулем или потенциально загрузить его на Appcelerator Marketplace.
Варианты упаковки мобильного модуля Titanium

Мы собираемся пойти дальше и выбрать первый вариант, создать пакет и сохранить его в нашей папке Titanium SDK. Выберите это и нажмите « Готово ». Теперь просто сядь и подожди минуту. Titanium Studio создаст ваш новый модуль, и когда он будет завершен, в правом нижнем углу экрана появится желтое уведомление. Успех!

Модуль Пакет Успех!

Теперь, когда наш модуль упакован, мы должны его протестировать, верно? Давайте создадим новый мобильный проект. Выберите Titanium Classic в меню шаблонов, а затем « Проект по умолчанию» . Мы собираемся создать наш пример проекта в очень простом, «классическом» коде Titanium. Это потому, что, как только он заработает, мы захотим скопировать наш тестовый код в файл example.js нашего модуля, чтобы другие люди могли использовать его в качестве ссылки. Я вызываю мое тестовое приложение Picasa-TestApp с идентификатором приложения com.boydlee.picasatestapp , но вы можете называть свое как угодно.

Создание нового проекта Titanium Mobile «Classic»

Этот базовый шаблон состоит из TabGroup и двух окон, все они определены в вашем файле app.js. Мы собираемся упростить код, чтобы у нас была только одна вкладка и одно окно. Мы добавим TableView, который мы будем заполнять данными наших альбомов, но прежде чем мы это сделаем, нам нужно добавить наш новый модуль в наш тестовый проект. Откройте файл tiapp.xml , нажмите кнопку « + » рядом со списком модулей приложения, а затем выберите модуль Picasa, который мы упаковали в предыдущем разделе.

Добавление модуля Picasa в наш тестовый проект

Теперь давайте добавим тестовый код в app.js , который вернет список альбомов нашему пользователю и покажет их в виде таблицы. Мы также сделаем запрос и создадим новый объект Picasa через наш модуль.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
//require our Module and create a new instance of it
var PicasaModule = require(‘com.boydlee.picasa’);
var picasa = new PicasaModule.Picasa();
 
//set the username
picasa.setUsername(‘boydlee’);
//set the access level using our public ‘CONSTANTS’ object
picasa.setAccessLevel(picasa.ACCESS_LEVELS.PUBLIC);
 
 
// this sets the background color of the master UIView (when there are no windows/tab groups on it)
Titanium.UI.setBackgroundColor(‘#000’);
 
// create tab group
var tabGroup = Titanium.UI.createTabGroup();
 
 
//
// create base UI tab and root window
//
var win = Titanium.UI.createWindow({
    title:’Picasa Albums’,
    backgroundColor:’#000′
});
var tab1 = Titanium.UI.createTab({
    icon:’KS_nav_views.png’,
    title:’Albums’,
    window: win
});
 
//get the albums for this user and access level
picasa.getAlbums(function(response){
   //openAlbumPhotosView(response.feed.entry[0].gphoto$name.$t, response.feed.entry[0].link[0].href);
   var table = Ti.UI.createTableView({
       width: Ti.UI.FILL,
       height: Ti.UI.FILL,
       top: 0,
       left: 0
   });
   table.addEventListener(‘click’, function(e){
       openAlbumPhotosView(e.row.data.title, e.row.data.url);
   });
    
   var rows = [];
    
   for(var i = 0; i < response.length; i++){
       var img = Ti.UI.createImageView({
           width: 60,
           height: 60,
           highres: true,
           image: response[i].thumbnail,
           left: 5,
           top: 5
       });
       var label = Ti.UI.createLabel({
           text: response[i].title,
           height: 60,
           font: {
               fontSize: 20,
               fontWeight: ‘bold’
           },
           top: 5,
           left: 80,
           width: Ti.UI.SIZE
       });
        
       var row = Ti.UI.createTableViewRow({
           className: ‘albumRow’,
           height: 70,
           data: response[i]
       });
        
       row.add(img);
       row.add(label);
       rows.push(row);
   }
    
   table.setData(rows);
   win.add(table);
});
 
// add tab
tabGroup.addTab(tab1);
 
 
// open tab group
tabGroup.open();

Обратите внимание, что я установил доступ public и имя пользователя boydlee , что позволит получить доступ к фотографиям в моей учетной записи Picasa. Как только это будет сделано, попробуйте запустить приложение в симуляторе.

Наше окно по умолчанию со списком альбомов Picasa, отображаемым в табличном представлении

Наконец, нам нужно добавить функцию openAlbumPhotosView , которая будет принимать заголовок и URL-адрес альбома, открыть новое окно на текущей вкладке, а затем вернуться назад и отобразить все фотографии для этого альбома в ScrollableView.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
function openAlbumPhotosView(title, url){
    Ti.API.info(‘Getting photos for album: ‘ + title);
    var detailsWin = Ti.UI.createWindow({
        title: title,
        backgroundColor: ‘#000’,
        height: Ti.UI.FILL,
        width: Ti.UI.FILL
    });
     
     
    picasa.getPhotosByUrl(url, function(response){
        Ti.API.info(response);
        var imageViews = [];
         
        for(var i = 0; i < response.length; i++){
            var img = Ti.UI.createImageView({
                image: response[i].url,
                title: response[i].title
            });
             
            imageViews.push(img);
        }
         
        var scrollableView = Ti.UI.createScrollableView({
           height: Ti.UI.FILL,
           width: Ti.UI.FILL ,
           views: imageViews
        });
     
        detailsWin.add(scrollableView);
    });
     
    tab1.open(detailsWin);
}

Запустите свой код в симуляторе в последний раз. Теперь вы сможете извлечь список альбомов, выбрать один из них в TableView, а затем просмотреть прокручиваемое слайд-шоу фотографий для этого альбома. Ухоженная!

ScrollableView показывает все фотографии из нашего выбранного альбома Picasa.

Теперь осталось только упаковать модуль Picasa для iOS и Android. Сначала скопируйте весь код из вашего тестового файла app.js и вставьте его в /example/app.js проекта модуля . Мы хотим, чтобы этот код был примером для других людей, которые хотят использовать наш модуль. Как только это будет сделано, просто нажмите кнопку « Пакет» , и вы сможете экспортировать свой модуль через местоположение , как мы объясняли в разделе « Упаковка и тестирование нового модуля ». Для Android процесс такой же, но мы должны создать отдельный проект модуля для этого, на этот раз создав новый проект Mobile Module для Android. Скопируйте и вставьте файлы с примерами / app.js и com.boydlee.picasa.js, которые мы уже создали, в нужные места в вашем проекте мобильного модуля Android. Затем вы можете создавать и распространять для Android, как мы это делали в iOS!

Совет: вам может понадобиться установить JDT, прежде чем вы сможете создавать модули для Android. Простое пошаговое руководство доступно на appcelerator.com


Надеюсь, вы нашли этот урок полезным. В следующий раз, когда вы подумаете о создании функциональности Titanium, которой вы хотите поделиться, или использовать в нескольких проектах, вы, вероятно, подумаете о том, чтобы обернуть ее в модуль CommonJS!