Показаны сообщения с ярлыком xCode. Показать все сообщения
Показаны сообщения с ярлыком xCode. Показать все сообщения

8 сентября 2011 г.

Отключение ARC в xCode 4.2

Нужно всего лишь в качестве компилятора в свойствах проекта выбрать "LLVM GCC 4.2" вместо установленного по умолчанию "Apple LLVM compiler 3.0".



PS: По совету твиттер пользователя @iLeNsTR можно обойтись флагами компилятора:

4 апреля 2011 г.

xcodebuild сборка приложения в консоли

Давно не писал в блог, времени катастрофически не хватало, впредь обещаю исправится.)

А для начала небольшой пост, о том, как можно сделать билд приложения в консоли.
Утилита xcodebuild из комплекта xCode SDK именно для этого. Хотя наверняка даже наоборот xcode IDE - графическая обертка над xcodebuild. Я

xcodebuild работает с проектом в текущей папке. Рассмотрим несколько основных параметров утилиты.
Запускается так:
$ xcodebuild [-project <projectname>] [-activetarget] [-alltargets] [-target<targetname>]... [-parallelizeTargets] [-activeconfiguration] [-configuration<configurationname>] [-sdk <sdkfullpath>|<sdkname>] [-xcconfig <filepath>][<buildsetting>=<value>]... [<buildaction>]...
из испольуемых мной параметров:

-target - задает имя таргета, который собирать в приложении
-configuration - задает конфигурацию, которую собирать
-sdk - и SDK который использовать при сборке
-list - показывает список таргетов и конфигураций для проектов в текущей папке
-showsdks - показывает доступные SDK

более детально можно узнать из мануалов:
$ man xcodebuild
В качестве "бонуса" приведу пример баш скрипта, который собирает приложение с конфигурацией "Distribution" и создает *.ipa файл. Подразумевается, что конфигурация "Distribution" настроена на подписку приложения сертификатом Ad-Hoc. Скрипт не проверяет ошибки вывода комманд, да и написался он быстрее чем этот пост:
#!/bin/sh
cd ~/work/my_project/trunk/my_project
rm -fr ./build
xcodebuild -target my_project -configuration Distribution -sdk iphoneos4.3
rm -fr ../tmp
mkdir ../tmp
mkdir ../tmp/Payload
cp -r ./build/Distribution-iphoneos/my_project.app ../tmp/Payload/
cp ./Resources/icon\@2x.png ../tmp/iTunesArtwork
cd ../tmp/
zip -r7 my_project.zip ./iTunesArtwork ./Payload
mv ./my_project.zip ../my_project.ipa
cd ..
rm -fr ./tmp

cp ./my_project.ipa ~/Desktop

23 февраля 2011 г.

Ошибка xCode Command .../copystrings failed with exit code 1

При сборке билда iPhone приложения xCode сегодня выдал ошибку:
Command /Developer/Library/Xcode/Plug-ins/CoreBuildTasks.xcplugin
/Contents/Resources/copystrings failed with exitcode 1
Решилась довольно просто, в фале "Localizable.strings" забыл в конце строки проставить ";"

16 октября 2010 г.

Органайзер Xcode говорит "Could not support development"

Сегодня при подключении своего iPhone и попытки скомпилировать и установить на него свое приложение Xcode начал ругаться на то, что к нему не подключено ни одно устройство. Органайзер Xcode видел устройство, но говорил, что оно не может использоваться для разработки (Could not support development). Хотя iTunes синхронизировался хорошо.

Все сертификаты разработчика внешне были в порядке, но для надежности обновил все сертификаты. Проблеммы не решило.

Решило проблемму самое логичное из всех действий, которые нужно проводить в таких случаях: перезагрузка устройства.

15 октября 2010 г.

Локализация строк в Xcode

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

С помощью Xcode можно локализировать:
- статический текст в коде программы
- ресурсы (иконки, рисунки, звуковые файлы, nib-файлы)
- вывод даты/времени

В этой заметке я расскажу о локализации статического текста в коде программы.

Локализация текста в коде программы необходима если, например, в коде программы задается текст который потом показывается пользователю (это может быть название кнопок, текст отчета и т.п.). Перед локализацией необходимо интернационализировать код программы. Для этого любой текст который показывается пользователю необходимо обвернуть макросом NSLocalizedString. Если раньше вы показывали диалог таким способом:

  1. UIAlertView *tmp = [[UIAlertView alloc] initWithTitle:@"Warning" message:@"Your e-mail application not configured" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
  2. [tmp show];
  3. [tmp release];


то теперь показываем так:

  1. UIAlertView *tmp = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Warning", @"") message:NSLocalizedString(@"Your e-mail application not configured", @"") delegate:nil cancelButtonTitle:NSLocalizedString(@"OK", @"") otherButtonTitles:nil];
  2. [tmp show];
  3. [tmp release];


Макрос NSLocalizedString вызывает метод localizedStringForKey:value:table: обьекта NSBundle приложения, которая возвращает локализированную строку.

Теперь нужно создать файл Localizable.strings, который будет шаблоном для файлов локализации. Для этого в терминале переходим в папку Classes приложения и выполняем команду:

  1. $ genstrings ./*.m


В результате в той же папке будет находиться файл Localizable.strings который и добавляем в проект (кодировку файла указываем UTF-16).



Теперь осталось локализировать этот файл на нужный нам язык. Для этого открываем свойства добавленного в проект файла Localizable.strings.



На вкладке "General" нажимаем кнопку "Маке File Localizable"



Переходим обратно на вкладку "General" и там добавляем локализацию



При этом в проекте создается папка с локализацией для этого языка и в нее помещаются файл Localizable.strings который нужно перевести на указанный язык. В проекте это выглядит так:



Файл Localizable.strings представляет собой пары "ключ" = "значение", где ключом выступает параметр переданный в макрос NSLocalizedString а значением - локализированная строка

  1. "Done" = "Готово";


См. также:
1. Локализация даты/времени

2 октября 2010 г.

Добавление изображений в Фотоальбом

Этот пост посвящен единственной функции из фраемворка UIKit, а именно UIImageWriteToSavedPhotosAlbum. В параметры функции передается изображение класса UIImage, а так-же функция-селектор которая вызовется после добавления изображения в Фотоальбом, либо при возникновении ощибки добавления.

Скачать пример.

10 сентября 2010 г.

Подключение проекта статической библиотеки к вашему проекту в xCode

Сейчас я не буду рассказывать о прелестях использования статических библиотек при программировании для iPhone, а просто опишу как подключить проект статической библиотеки к вашему проекту. Итак, у вас имеется проект статической библиотеки и проект (буду его называть проектом приложения) в который вы хотите ее подключить.

Открываем в xCode проект приложения. В Finder переходим в папку проекта статической бибилотеки и перетаскиваем файл проекта в xCode


Идем в меню Project->Edit Active Target "…". В появившемся окне жмем на "+" на вкладке "General" в группе "Direct Dependencies" и выбираем статическую библиотеку только-что добавленную в проект.


после добавления


а так выглядит "Group & Files" в окне проекта приложения


теперь нужно сказать xCode, что при сборке этого таргета необходимо прилинковывать нашу статическую библиотеку. Для этого перетаскиваем библиотеку и проекта библиотеки в секцию "Link Binary With Libraries" таргета приложения.


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

Если ваша статическая библиотека использует классы ObjectiveC, то в свойствах проекта добавте ключ -ObjC к "Other Linker Flags"



Пример.

3 сентября 2010 г.

Создание шаблонов приложений в xCode (часть 2)

В первой части я рассказывал о создании проекта в шаблоне xCode. В этой части разберем файл TemplateChooser.plist и отличие проекта шаблона от обычного проекта.

В файле TemplateChooser.plist расположено описание окна "New Project" выбраного шаблона, а так же набор правил выбора проекта из шаблона в зависимости от выбраных пользователем параметров шаблона.


Приведенный пример представлен хешом из 4-х элементов: "Checkboxes", "OptionsLabel", "PopupMenu" и "TemplateSelection". Первые три отвечают за внешний вид она "New Project" при выбраном шаблоне, TemplateSelection - за правила выбора проекта из шаблона.

Секции Checkboxes это массив чекбоксов, а PopupMenu отвечает за пункты во всплывающем списке при выборе шаблона. OptionsLabel отвечает только за заголовок. Каждый элемент этих массивов имеет уникальный идинтификатор (Key) и строку описания(Title) которая выводится как имя элемента.

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

Например в таком варианте:


будет использоваться ключ "iPhoneStorage"

Сам проект в шаблоне тоже немного отличается от стандартного проекта. В папке проекта содержаться два файла: TemplateIcon.icns и TemplateInfo.plist. Первый - иконка шаблона, второй - краткое описание шаблона.


30 августа 2010 г.

Создание шаблонов приложений в xCode (часть 1)

Часто при создании новых проектов приходится выполнять много рутинной работы: добавлять фраемворки и библиотеки, создавать стандартные классы и т.д. Стандартные шаблоны дают только общие несколько классов. В моих проектах всегда присутствует несколько стандартных классов, которые в процессе программирования обрастают разной функциональностью (так что их в библиотеки пихать нельзя). Я решил разобраться с механизмом шаблонов в xCode.

Шаблоны xCode лежат в папках:
/Developer/Library/Xcode/Project Templates/ - для Mac OS X проектов
/Developer/Platforms/iPhoneOS.platform/Developer/Library/Xcode/Project Templates/ - для iOS проектов

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



Эта папка состоит из одного или нескольких проектов xCode и файла с правилами выбора проекта из этого списка (TemplateChooser.plist).



Несколько проектов в шаблоне из-за того, что при выборе шаблона в xCode можно ввести дополнительные возможности при создании проекта (будь то добавление CoreData сервисов, поддержку iPad устройства, или создание универсального проекта), и для всех этих возможностей нужно создавать отдельный проект. В стандартных шаблонах имена довольно понятны, чтоб понять какую функциональность добавляет каждый проект. Их то нужно править.

Открываем проект в xCode. И делаем с ним все что пожелаем: добавляем классы, ресурсы, plist-ы. При добавлении файлов свойство "Path type" выставляйте в "Relative to Enclosing Group".



После перезагрузки xCode при создании нового проекта появиться созданный шаблон



Если вы компилировали проект шаблона, не забудьте удалить папку "build" из проекта шаблона.

В этой статье ничуть не затронут файл TemplateChooser.plist, трогаем во второй части.

27 августа 2010 г.

Создание .ipa-архива из .app

1. Создаем папку Payload
2. Копируем в нее папку *.app
3. По желанию можно иконку приложения переименовать в iTunesArtwork
4. Упаковываем Payload и iTunesArtwork обычным zip архиватором

5. Переименовываем .zip архив в .ipa

Полученный файл .ipa можно добавлять в iTunes и синхронизировать с мобильным устройством.

PS: iTunes так-же поймет если в него кинуть папку .app

25 августа 2010 г.

Запись аудио с микрофона iPhone

Во времена прошивок 2.х для меня стало открытием, что подключив гарнитуру к iPod Touch можно использовать микрофон для записи аудио. А вот в 3-й прошивке появилось приложение "Диктофон", так что возможность подключения микрофона стала очевидной.

Есть несколько способов записи звука с вашего приложения. Я расскажу о наборе функций из фраемворка AudioToolbox.

Запись осушествляется через специально подготовленные буфера, по мере их заполнения они отсылаются функции-слушателю, а там уже программист решает: записать буфер в файл, отправить в сеть или обработать как-то по своему. Но для начала нужно все подготовить.

Для задания формата входного буфера и параметров аудио используется структура AudioStreamBasicDescription. Эта структура передается в функцию AudioQueueNewInput, эта функция создает новый объект для записи.

  1. AudioStreamBasicDescription mDataFormat;
  2. mDataFormat.mFormatID = kAudioFormatLinearPCM;
  3. mDataFormat.mSampleRate = 44100;
  4. mDataFormat.mChannelsPerFrame = 1;
  5. mDataFormat.mBitsPerChannel = 16;
  6. mDataFormat.mBytesPerPacket =
  7. mDataFormat.mBytesPerFrame = mDataFormat.mChannelsPerFrame * sizeof(short int);
  8. mDataFormat.mFramesPerPacket = 1;
  9. mDataFormat.mFormatFlags = kLinearPCMFormatFlagIsBigEndian
  10. | kLinearPCMFormatFlagIsSignedInteger
  11. | kLinearPCMFormatFlagIsPacked;
  12. AudioQueueRef queue;
  13. AudioQueueNewInput(&mDataFormat, AQInputCallback,
  14. NULL, NULL, kCFRunLoopCommonModes, 0, &queue);


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

Теперь необходимо подготовить аудиобуферы в которые будет помещаться считанный аудиопоток. Функция AudioQueueAllocateBuffer выделяет память под буфер, а AudioQueueEnqueueBuffer добавляет к нашему объекту для записи полученный функцией AudioQueueNewInput.

  1. unsigned long frameSize = mDataFormat.mSampleRate * mDataFormat.mBytesPerFrame;
  2. AudioQueueBufferRef aBuffers[AUDIO_BUFFERS];
  3. for (int i=0; i<AUDIO_BUFFERS; i++)
  4. {
  5. AudioQueueAllocateBuffer(queue, frameSize, &aBuffers[i]);
  6. AudioQueueEnqueueBuffer(queue, aBuffers[i], 0, NULL);
  7. }


Подготовка закончена. Запускаем запись аудио функцией AudioQueueStart.

  1. AudioQueueStart(queue, NULL);


Остановить запись можно функцией AudioQueueStop:

  1. AudioQueueStop(queue, true);


И освобождение памяти от объекта queue функцией AudioQueueDispose

  1. AudioQueueDispose(queue, true);


Пример от Apple SpeakHere мне показался большим и сложным для понимания, мой более компактный.

24 августа 2010 г.

FileSharing копирование файлов через iTunes на/с iPhone

Начиная с версии 4.0 в iOS есть поддержка копирования пользовательских файлов на или с вашего iУстройства через iTunes (начиная с версии 9.1). Находится это в секции "Программы":



Эта папка из вашего приложения видна как папка "Documents"

Для включения поддержки в ваше приложение вам программировать практически ничего не нужно. В Info.plist вашего приложения включите ключ UIFileSharingEnabled и присвойте ему значение YES. Так iTunes понимает что папка "Documents" этого приложения доступна для передачи файлов.



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

  1. NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
  2. NSUserDomainMask, YES);
  3. NSError *error;
  4. NSFileManager *fileManager = [NSFileManager defaultManager];
  5. NSLog(@"%@", [fileManager contentsOfDirectoryAtPath:[paths objectAtIndex:0] error:&error]);


Небольшой пример.

18 августа 2010 г.

Размер клавиатуры в iOS

Иногда необходимо узнать размер виртуальной клавиатуры из приложения. Например чтоб изменить положение/размер ваших визуальных компонентов на view. До появления iPad/iPhone 4 можно было смело использовать константы. С выходом устройств с различным разрешением экрана константы использовать нельзя.

Первое, что нам понадобится, зарегистрировать слушателя на появление клавиатуры на экране (делается это например в методе viewDidAppear: вашего UIViewController):

  1. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShown:) name:UIKeyboardWillShowNotification object:nil];

в конце не забываем отписаться от получения сообщений повеления клавиатуры

  1. [[NSNotificationCenter defaultCenter] removeObserver:self];

а вот и сама функция-слушатель:

  1. - (void) keyboardWillShown:(NSNotification*) aNotification
  2. {
  3.   NSDictionary* info = [aNotification userInfo];
  4.  
  5.   #ifdef __IPHONE_4_0
  6.   NSValue* aValue = [info objectForKey:UIKeyboardBoundsUserInfoKey];
  7.   if (!aValue)
  8.   {
  9.     aValue = [info objectForKey:UIKeyboardFrameEndUserInfoKey];
  10.   }
  11.   #else
  12.   NSValue* aValue = [info objectForKey:UIKeyboardBoundsUserInfoKey];
  13.   #endif
  14.  
  15.   CGSize keyboardSize = [aValue CGRectValue].size;
  16.   NSLog(@"%.1fx%.1f", keyboardSize.width, keyboardSize.height);
  17. }

тут мы просто печатаем в лог размер виртуальной клавиатуры.

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

16 августа 2010 г.

Установка приложения на устройство с прошивкой 3.х из Xcode 3.2.4

Аpple из новых версий Xcode убрали iPhone Simulator версий 2.х и 3.х. Так же базовой версией SDK можно поставить только версии 4.х. Не обязательно держать установленным две версии Xcode для поддержки из вашего приложения версий 3.х и 4.х. Из новой версии Xcode можно устанавливать приложения на устройства с прошивкой 3.0, для этого нужно в свойствах проекта выставить свойство "iOS Deployment Target" на нужную версию SDK вашего устройства.

По комментариям статьи.

PS: перед использованием функций которых нет в более ранних версиях SDK следует проверять их наличие

  1. if ([obj respondsToSelector:@selector(someSelector:)])
  2. {
  3.   [obj performSelector:self withObject:nil];
  4. }

7 августа 2010 г.

Информация о сети

В iOS 4.0 Apple дала возможность разработчикам получить информацию о сети в которой находится телефон, а так-же о текущих звонках. Итак, фраемворк CoreTelephony. Он представлен всего несколькими классами, но из них можно вынести интересную информацию. Класс CTCarrier содержит информацию о сети, CTCall - о текущем звонке. Подписаться на получение изменений информации о звонках и изменении сети можно зарегистрировав слушателей subscriberCellularProviderDidUpdateNotifier и callEventHandler в классах CTTelephonyNetworkInfo и CTCallCenter.

Простой пример

4 августа 2010 г.

Local Notifications в iOS 4.0

Начиная с iOS SDK 4.0 появилась возможность отсылать локальные сообщения. Локальные сообщения - это сообщения пользователю от вашей программы в определенное время, не зависимо от того, запущено ли ваше приложение. Очень похоже на Push Notification но действует только в пределах одного устройства (без участия севера). Как и Push Notification Local Notification может быть доставлен пользователю как: звуковое сообщение, цифра на иконке приложения и как алерт. Не думайте, что при посылке Local Notification ваше приложение запустится, это произойдет только в том случае, если ваше Local Notification имеет тип алерт и пользователь на этом всплывающем окне нажал кнопку "View". Так что никакой важной информации не стоит доставлять через Local Notification, хотя эти сообщения и надежнее чем Push Notification так как не зависят от состояния сети.

Регистрация в системе Local Notification осуществляет метод scheduleLocalNotification: класса UIApplication. Параметром этого метода служит объект класса UILocalNotification. Код который осуществляет отсылку сообщения:

  1. UILocalNotification* alarm = [[[UILocalNotification alloc] init] autorelease];
  2.  if (alarm)
  3.  {
  4.   alarm.fireDate = [[NSDate date] dateByAddingTimeInterval:30.0];
  5.   alarm.timeZone = [NSTimeZone defaultTimeZone];
  6.   alarm.repeatInterval = 0;
  7.   alarm.alertBody = @"local notification";
  8.   UIApplication *app = [UIApplication sharedApplication];
  9.   [app scheduleLocalNotification:alarm];
  10.  }

Этот код создает объект alarm типа alert c текстом "local notification" и регистрирует его в системе как событие, которое произойдет через 30 сек.

Посмотреть зарегистрированные в системе от вашего приложении нотификации позволяет метод scheduledLocalNotifications. Отменить все нотификации можно методом cancelAllLocalNotifications.

Что э происходит если событие нотификации происходит при запущенном приложении? Системных событий тогда никаких не происходит (не звуков не проигрывается, не показывается всплывающее окно), но делегату вашего приложения приходит событие application:didReceiveLocalNotification: в котором можно обработать сообщение.

Пример работы.

27 июля 2010 г.

MapKit в iOS

В моем старом приложении требовалась поддержка прошивки iPhone OS 2.х. Поэтому я не мог использовать все прелести фраемворка MapKit, который появился в 3.0 прошивке. В те далекие времена (около года назад) я отображал карту через UIWebView. Так как сейчас количество устройств с установленной на них прошивками 2.х ничтожно мало, было принято решение переходить на встроеные компоненты отображения карты.

Отобразить в вашем приложении карту можно используя класс MKMapView из фраемворка MapKit. Класс представляется множеством очевидных методов: mapType, zoomEnabled, region, showUserLocation, которые настраивают внешний вид карты. Но это все просто, мне было интересно добавлять на карту свои объекты. С этим мы и будем разбираться в данной статье.

Для добавления на карту элемента привязанного к одной геокоординате используется метод addAnnotation:. В качестве аргумента он принимает объект который наследует протокол MKAnnotation. Протокол реализует методы задания координаты нашей аннотации (coordinate), задание заголовка аннотации (title) и ее текста (subtitle). Вот самый простой пример объекта аннотации:

marker.h
  1. @interface marker : NSObject <MKAnnotation>
  2. {
  3. }
  4. @end


marker.m
  1. #import "marker.h"
  2.  
  3. @implementation marker
  4. #pragma mark MKAnnotation
  5. - (CLLocationCoordinate2D) coordinate
  6. {
  7.   return CLLocationCoordinate2DMake(46.46258530.750186);
  8. }
  9.  
  10. - (NSString *) title
  11. {
  12.   return @"This annotation";
  13. }

создадим экземпляр этого объекта и добавим его на карту:

  1. marker *= [[marker alloc] init];
  2. [mapView addAnnotation:m];
  3. [m release];

довольно просто, правда ведь? Если мы хотим кустимизировать нашу аннотацию, например изменить иконку иголочки, то нам необходимо использовать метод mapView:viewForAnnotation: делегата нашей карты, пример приведен в конце статьи.

Пусть теперь мы хотим нарисовать на карте объект привязанный к нескольким геокоординатам (например маршрут из точки А в точку В). Тут нужно добавлять не аннотацию, а оверлей addOverlay:. Добавим в него MKPolyline:

  1. CLLocationCoordinate2D mapCoords[6];
  2. mapCoords[ 0] = CLLocationCoordinate2DMake(46.476472, 30.704776);
  3. mapCoords[ 1] = CLLocationCoordinate2DMake(46.469664, 30.732229);
  4. mapCoords[ 2] = CLLocationCoordinate2DMake(46.462585, 30.750186);
  5. mapCoords[ 3] = CLLocationCoordinate2DMake(46.447197, 30.743040);
  6. mapCoords[ 4] = CLLocationCoordinate2DMake(46.415384, 30.723226);
  7. mapCoords[ 5] = CLLocationCoordinate2DMake(46.409143, 30.729909);
  8. MKPolyline *polyLine = [MKPolyline polylineWithCoordinates:mapCoords count:6];
  9. [mapView addOverlay:polyLine];
  10. [mapView setDelegate:self];


и в делегате нашей карты зададим свойства этой линии

  1. - (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id <MKOverlay>)overlay
  2. {
  3.  MKPolylineView *polylineView = [[[MKPolylineView alloc] initWithOverlay:overlay] autorelease];
  4.  polylineView.strokeColor = [UIColor blueColor];
  5.  polylineView.lineWidth = 3.0;
  6.  return polylineView;
  7. }


Пример проекта.

Так же смотрите:
- Конвертирование "человеческого" адреса в широту и долготу

21 июля 2010 г.

Работа с музыкальной библиотекой iPod в iOS

Возникла у меня задача, проверить программно, присутствует ли конкретная песня в библиотеке пользователя на iPhone/iPod Touch, и если есть, то проиграть ее. Итак, будем программировать работу с библиотекой iPod.

Для взаимодействия с музыкальной библиотекой в iOS существует класс MPMusicPlayerController из фраемворка MediaPlayer. Функций вроде и не много, но они покрывают практически все возможности приложения iPod.app. При создании экземпляра класса можно выбрать, каким плейером будем пользоваться, созданным отдельно для приложения(метод applicationMusicPlayer), или глобальным плейером iPod(метод iPodMusicPlayer). Первый выгрузится при закрытии приложения, второй может продолжать работать после закрытия приложения. Будем работать с глобальным плейером iPod.

Вызвав метод play мы уже можем услышать музыку доносящуюся из динамиков устройства (iPhone Sumulator не подключается к библиотеке iTunes). Если нужно знать, когда закончилась/сменилась песня нужно зарегистрировать слушателя:

  1. MPMusicPlayerController *ipod = [MPMusicPlayerController iPodMusicPlayer];
  2. [[NSNotificationCenter defaultCenter] addObserver:self
  3.   selector:@selector(playbackItemChanged:)
  4.   name:MPMusicPlayerControllerNowPlayingItemDidChangeNotification
  5.   object:ipod];
  6. [ipod beginGeneratingPlaybackNotifications];

тут мы регистрируем функцию playbackItemChanged: текущего класса как слушателя события изменения песни в iPod.

Хорошо, сейчас мы можем прослушивать песни из пленэра, но не можем выбирать, что слушать. Звуковой файл представляется в библиотеке классом MPMediaItem. Но просто так его создать нельзя, его нужно получать фильтруя из музыкальной библиотеки данные. Для фильтрации используется класс MPMediaQuery. Тут можно отфильтровать библиотеку по разным множеству категориям (таким как жанр, аудиокниги, подкасты, плечисты), а также можно добавлять свои фильтры.

  1. [ipod setQueueWithQuery:[MPMediaQuery songsQuery]];
  2. [ipod play];

И по традиции пример приложения.

16 июля 2010 г.

Проигрывание музыки с помощью iPhone SDK

Присутствие звуковых эффектов и музыки сильно улучшает ваше приложение. Сегодня я расскажу как с помощью iPhone SDK управлять проигрыванием звукового файла. Речь пойдет о проигрывали больших звуковых файлов с возможностью приостановки и изменении позиции проигрывания.
Я буду использовать класс AVAudioPlayer из фраемворка AVFoundation. Напишем приложение которое будет циклически проигрывать файл с возможностью перемотки. Я не использую Interface Builder поэтому не буду приводить скриншоты расположения элементов на экране. Итак, в в нашем вью присутствует кнопка старта/остановки проигрывания (playStopBtn), слайдер показывающий позицию в проигрываемом файле (tmSlider) и свичер разрешающий играть музыку при залоченом экране.
Первое, что необходимо сделать, так это создать наш плейер и настроить его. Например в методе init или loadView прописываем:

  1. NSURL *file = [[NSURL alloc] initFileURLWithPath:
  2.     [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"a_hot.caf"]];
  3. NSError *err = nil;
  4. player = [[AVAudioPlayer alloc] initWithContentsOfURL:file error:&err];
  5. [file release];
  6. player.numberOfLoops = -1;
  7. player.delegate = self;
  8. [player prepareToPlay];

в результате плейер у нас создан, и в него загружен наш звуковой файл.
Описываем событие нажатия на кнопку playStopBtn:

  1. if (player.playing)
  2. {
  3.  [player stop];
  4.  [playStopBtn setTitle:NSLocalizedString(@"Play", @"") forState:UIControlStateNormal];
  5.  [tmUpdaterTimer invalidate];
  6.  [tmUpdaterTimer release];
  7.  tmUpdaterTimer = nil;
  8. }
  9. else
  10. {
  11.  [player play];
  12.  [playStopBtn setTitle:NSLocalizedString(@"Stop", @"") forState:UIControlStateNormal];
  13.  tmUpdaterTimer = [[NSTimer scheduledTimerWithTimeInterval:0.2
  14.  target:self selector:@selector(timerAction:)
  15.  userInfo:nil repeats:YES] retain];
  16. }

тут все просто, если сейчас играет музыка - останавливаем ее проигрывание, исли плейер на паузе - начинаем проигрывание. Так-же тут создается/уничтожается таймер, который изменяет позицию слайдера при проигрывали:

  1. - (void) timerAction:(NSTimer *) sender
  2. {
  3.   [tmSlider setValue:player.currentTime animated:YES];
  4. } 

У слайдера показывающего позицию в проигрываемом файле тоже есть два слушателя на изменение позиции и окончание изменения позиции:

  1. - (void) changeTime:(UISlider *) sender
  2. {
  3.   if (!moving)
  4.   {
  5.     isPlaying = player.playing;
  6.     if (player.playing)
  7.     {
  8.       [player stop];
  9.     }
  10.     moving = YES;
  11.   }
  12.   player.currentTime = sender.value;
  13. }
  14.  
  15. - (void) endChangeTime:(UISlider *) sender
  16. {
  17.   moving = NO;
  18.   if (isPlaying)
  19.   {
  20.     [player play];
  21.   }
  22. }

при начале перетаскивания ползунка проверяем, играет ли музыка, если да, то приостанавливаем проигрывание в конце востанавливаем состояние.

Все проигрывается, но при блокировке экрана музыка приостанавливается. Следующий код разрешает проигрывание музыки при выключенном экране устройства:

  1. AudioSessionInitialize(NULL, kCFRunLoopDefaultMode, NULL, self);
  2. UInt32 sessionCategory = kAudioSessionCategory_MediaPlayback;
  3. AudioSessionSetProperty(kAudioSessionProperty_AudioCategory, sizeof(sessionCategory), &sessionCategory);
  4. AudioSessionSetActive(true);

Мой пример использующий все выше написанное можно скачать

13 июля 2010 г.

Отсылка почты из вашего приложения встроенным клиентом Mail в iOS

Вот решил написать несколько статей по программированию под iPhone/iPod Touch/iPad.
Для начала выбрал простенькую тему описывающуюся одним классом в SDK и несколькими методами. Итак, отсылка почты из вашего приложения встроенным клиентом Mail.
Работу отсылки почты осуществляет класс MFMailComposeViewController наследник от стандартного UIViewController-а. Первое, что необходимо сделать, это подключить к вашему проекту фраемворк MessageUI.

Потом подключить описание этого фраемворка.

Теперь можно кодить.

  1. // Перед тем как вызывать диалог отсылки почты необходимо проверить настроен ли у пользователя вообще почтовый клиент.
  2. if (![MFMailComposeViewController canSendMail])
  3. {
  4.   // Клиент не настроен, показываем всплывающее окно.
  5.  UIAlertView *tmp = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Warning", @"") message:NSLocalizedString(@"Your e-mail application not configured", @"") delegate:nil cancelButtonTitle:NSLocalizedString(@"OK", @"") otherButtonTitles:nil];
  6.  [tmp show];
  7.  [tmp release];
  8.  return ;
  9. }
  10.  // создаем экземпляр обекта MFMailComposeViewController
  11. MFMailComposeViewController *mcvc = [[MFMailComposeViewController alloc] init];
  12.  // указываем обект делегата (слушателя)
  13. mcvc.mailComposeDelegate = self;
  14.  // заполняем поле "Кому"
  15. [mcvc setToRecipients:[NSArray arrayWithObject:@"test@example.com"]];
  16.  // заполняем поле "Тема"
  17. [mcvc setSubject:NSLocalizedString(@"Testing mail", @"")];
  18.  // пишем тело письма
  19. [mcvc setMessageBody:NSLocalizedString(@"This is body of mail", @"") isHTML:NO];
  20.  // прикрепляем к письму данные как текст и указываем имя файла приложения к письму
  21. [mcvc addAttachmentData:[@"Text on attach" dataUsingEncoding: NSUTF8StringEncoding] mimeType:@"text/plain" fileName:@"test.txt"];
  22.  // показываем заполненный контрол
  23. [self presentModalViewController:mcvc animated:YES];

Нужно помнить, что контрол сам не убирается после нажатия кнопки "Отправить", поэтому в методе слушателе (mailComposeController:didFinishWithResult:error:) закроем наш контрол:

  1. - (void) mailComposeController:(MFMailComposeViewController*) controller didFinishWithResult:(MFMailComposeResult) result error:(NSError*) error
  2. {
  3.  [controller dismissModalViewControllerAnimated:YES];
  4. }

Проект для xCode можно скачать.