- PVSM.RU - https://www.pvsm.ru -
Совсем недавно компания Xamarin анонсировала выход новой версии своего инструментария для кроссплатформенной разработки мобильных приложений, но вменяемых статей на русском по этой тематике так и нет. На Хабре появился небольшой обзор [1], не связанный с кодингом, там же была пара попыток [2] рассказать об этом чуть подробнее, но дальше процесса создания Hello World приложения дело не зашло. А жаль. В этот раз мы попробуем исправить это досадное недоразумение.
Инсталлятор Xamarin устанавливает плагин к Visual Studio, который позволяет разрабатывать приложения для популярных мобильных платформ в привычном разработчику окружении. Также устанавливается отдельная среда разработки Xamarin Studio, которая, судя по всему, является модифицированной версией MonoDevelop. Мне привычнее работать в Visual Studio поэтому примеры в этой статье будут показаны с использованием именно этой среды разработки.
После установки в Visual Studio добавляются шаблоны проектов для мобильных приложений под Android и iOS (поддерживается создание как специализированных приложений для iPad и iPhone, так и универсальных приложений, а также приложений, использующих OpenGL). Для создания приложений для iOS в Visual Studio прийдется, правда, заплатить. Этот функционал доступен либо в режиме trial, либо в business-версии инструментария, а это стоит $899 в год.
После создания проекта мы получаем все тот же API для каждой платформы, который мы имеем при нативной разработке, но синтаксис будет на C#, к тому же есть возможность использовать базовые типы .NET Framework, синтаксический сахар и прочие плюшки .NET.
После создания Android-проекта мы получаем набор файлов, в котором есть класс главного окна и набор ресурсных файлов. После длительной работы в Eclipse немного раздражает название папок в PascalCase, но к этому можно довольно быстро привыкнуть. Также есть отличия в работе с файлами ресурсов. Для того, чтобы встроенный дизайнер окон понимал файлы ресурсов с лайаутами, у них расширение изменено на .AXML вместо привычного .XML в Eclipse. Это довольно сильно раздражает, особенно если рисовать лайауты в Eclipse, а потом переносить в Visual Studio в случае если Eclipse’овский дизайнер окон больше нравится.
Встроенный дизайнер окон мне лично показался неудобным. Медленный, часто валит всю IDE, я так и не понял, как в нем по-простому переключиться между XML-видом и UI. Здесь уж точно можно сказать что писано чужими для хищников. Я для себя решил, что в Eclipse мне удобнее, привычнее, да и на экран ноутбука в Eclipse помещается больше полезной информации. Может кому-то дизайнер Visual Studio и понравится больше, на вкус и цвет фломастеры разные.
Код на C# для Mono for Android очень схож с кодом на Java.
namespace XamarinDemo.Android
{
[Activity(Label = "XamarinDemo.Android", MainLauncher = true, Icon = "@drawable/icon")]
public class MainActivity : Activity
{
int count = 1;
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
SetContentView(Resource.Layout.Main);
Button button = FindViewById<Button>(Resource.Id.MyButton);
button.Click += delegate { button.Text = string.Format("{0} clicks!", count++); };
}
}
}
Отличия, которые сразу видны:
Для получения ссылок на элементы управления, как и в Java-версии, используется метод FindViewById()
. Очень порадовало наличие generic-версии этого метода, который возвращает объект нужного типа и позволяет избавиться от c-cast’ов.
Вместо listener’ов, а точнее, в дополнение к ним, для подключения обработчиков событий используются делегаты. Можно использовать и listener’ы, но это, во-первых, не .NET way, во-вторых, требует написания большего количества кода, даже по сравнению с Java. К тому же делегатов можно подключить несколько:
Button button = FindViewById<Button>(Resource.Id.MyButton);
button.Click += delegate { button.Text = string.Format("{0} clicks!", count++); };
button.Click += (o, e) =>
{
Toast.MakeText(this, string.Format("{0} clicks!", count++), ToastLength.Long).Show();
};
Не со всеми обработчиками событий в виде делегатов дела обстоят радужно. В одном из проектов обнаружилась проблема с событием View.ViewTreeObserver.GlobalLayout
, у которого при использовании оператора -= не отключались делегаты-обработчики. Да вообще никак не отключались. Пришлось использовать IOnGlobalLayoutListener
.
В Mono for Android есть возможность использовать существующие JAR-файлы в приложении на C#. Для этих целей предусмотрен специальный тип проекта: Java Binding Library.
Для того, чтобы использовать JAR-библиотеку необходимо:
После этого можно использовать классы из JAR-файла. Необходимо учитывать, что имена пакетов в C# и в исходном Java-коде могут немного отличаться. Так, например, пакет com.example.androiddemolib из Java-кода будет переименован на Com.Example.Androiddemolib (то есть будет преобразован в PascalCase).
Неплохую инструкцию по использованию Java-библиотек можно почитать здесь [4].
Для работы с базами данных в Mono for Android предусмотрены используются классы пространства имен Mono.Data.Sqlite
(используются для доступа к базам данных SQLite) и System.Data.SqlClient
(для доступа к Microsoft SQL Server). Классы пространства имен System.Data.SqlClient
доступны только в Business-редакции инструментов разработки. Можно также использовать классы-обертки над родным Java API для Android и сторонние разработки, например sqlite-net, в котором доступен асинхронный вариант API.
Пользоваться доступным API довольно просто. Все очень схоже с разработкой для настольных ПК:
namespace XamarinDemo.Android
{
[Activity(Label = "XamarinDemo.Android",
MainLauncher = true, Icon = "@drawable/icon")]
public class MainActivity : Activity
{
SqliteConnection GetConnection(string path)
{
SqliteConnectionStringBuilder builder =
new SqliteConnectionStringBuilder();
if (!File.Exists(path))
{
FileInfo info = new FileInfo(path);
if (!Directory.Exists(info.Directory.FullName))
{
Directory.CreateDirectory(info.Directory.FullName);
}
SqliteConnection.CreateFile(path);
}
builder.DataSource = path;
return new SqliteConnection(builder.ToString());
}
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
SetContentView(Resource.Layout.Main);
try
{
string path = GetDatabasePath("xamarindemo.sqlite").Path;
SqliteConnection connection = GetConnection(path);
connection.Open();
SqliteCommand command = connection.CreateCommand();
command.CommandType = CommandType.Text;
command.CommandText = "CREATE TABLE IF NOT EXISTS DemoTable(" +
"id INTEGER AUTO_INCREMENT PRIMARY KEY NOT NULL" +
", name VARCHAR(32))";
command.ExecuteNonQuery();
connection.Close();
}
catch (Exception e)
{
System.Diagnostics.Debug.WriteLine(e.ToString());
}
}
}
}
Создание элементов управления в коде ничем не отличается от аналогичной работы в Objective-C. Обработчики событий можно навешивать также как и в Android – с помощью делегатов. Также можно добавлять обработчики как в Objective-C через селекторы.
namespace XamarinDemo.iOS
{
public class MyViewController : UIViewController
{
UIButton button;
…
public MyViewController()
{
}
public override void ViewDidLoad()
{
base.ViewDidLoad();
…
button = UIButton.FromType(UIButtonType.RoundedRect);
…
button.AddTarget(this,
new Selector("ButtonTouchInside"),
UIControlEvent.TouchUpInside);
…
button.TouchUpInside += (object sender, EventArgs e) =>
{
button.SetTitle(String.Format(
"clicked {0} times", numClicks++), UIControlState.Normal);
};
…
View.AddSubview(button);
}
[Export("ButtonTouchInside")]
void OnButtonTouchInside()
{
Console.WriteLine("Hello!");
}
}
}
В Xamarin iOS, также как и для Android, доступна возможность использования нативных библиотек. Для этих целей есть специальный тип проекта – iOS Binding Project, в который можно добавлять статические библиотеки, после чего они будут слинкованы вместе с основным проектом.
В общем виде, для использования нативной библиотеки в C# проекте необходимо сделать следующее:
@interface iOSDemoClass : NSObject
- (NSInteger) addData: (NSInteger) value1 andOtherValue: (NSInteger) value2;
@end
…
@implementation iOSDemoClass
-(NSInteger) addData: (NSInteger) value1 andOtherValue: (NSInteger) value2
{
return value1 + value2;
}
@end
xcodebuild -project iOSDemoLib.xcodeproj
-target iOSDemoLib -sdk iphonesimulator
-configuration Release clean build
xcodebuild -project iOSDemoLib.xcodeproj
-target iOSDemoLib -sdk iphoneos -arch armv7
-configuration Release clean build
lipo -create -output ../iOSDemoLib.Binding/libiOSDemoLib.a ../libiOSDemoLib-i386.a ../libiOSDemoLib-iphone-armv7.a
[assembly: LinkWith ("libiOSDemoLib.a", LinkTarget.Simulator | LinkTarget.ArmV7, ForceLoad = true, Frameworks = "Foundation")]
namespace iOSDemoLib.Binding
{
[BaseType (typeof(NSObject))]
interface iOSDemoClass
{
[Export("addData:andOtherValue:")]
int AddDataAndOtherValue(int value1, int value2);
}
}
Вообще, очень хорошо и доступно о привязке нативных библиотек написано здесь [5].
Для работы с базами данных в iOS используются те же пространства имен, что и в Android. API, соответственно, такой же. Небольшая разница может быть в мелочах. Например, для получения пути к файлу базы данных SQLite в Android есть специальный API-вызов:
string path = GetDatabasePath("xamarindemo.sqlite").Path;
В iOS же нужно использовать стандартные средства .NET:
string path = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.Personal),
"xamarindemo.sqlite");
В Xamarin 2.0 есть возможность отладки мобильных приложений для iOS прямо из Visual Studio. Для того, чтобы это стало возможно, необходимо иметь в локальной сети Mac с установленным XCode, iOS SDK и Xamarin Studio. Никаких дополнительных настроек производить не надо, достаточно при открытии iOS проекта в Visual Studio выбрать нужный build-сервер из списка доступных.
К сожалению данный подход не заработал с виртуальной машиной, запущенной на том же компьютере что и Visual Studio. Хотя с обычным Mac’ом в локальной сети все замечательно работает. Причин или объяснений этому пока найти не удалось, пытаюсь общаться с разработчиками по этому поводу.
Также не очень понятно, как организовывать UI-тестирование и проверку работоспособности приложения из Visual Studio. Симулятор запускается на Mac’е, похоже, что без VNC здесь не обойтись.
Xamarin предоставляют возможность создания библиотек, которые могут быть использованы (в виде кода или готовых сборок) сразу для нескольких платформ. Такие библиотеки называются Portable Class Library (PCL).
Для разработки подобных библиотек используется специальный урезанный вариант .NET Runtime и это чудесный инструмент для разработчика, значимость которого трудно переоценить, но здесь тоже не все так просто. По умолчанию в Visual Studio нельзя указать Android и iOS в качестве поддерживаемых платформ для PCL-проекта. Но это не значит, что Visual Studio сразу становится бесполезной в этом плане.
Проблему можно решить путем создания XML-файлов в папке C:Program Files (x86)Reference AssembliesMicrosoftFramework.NETPortablev4.0ProfileProfile104SupportedFrameworks
для x64 систем или в папке C:Program FilesReference AssembliesMicrosoftFramework.NETPortablev4.0ProfileProfile104SupportedFrameworks
для x86 систем.
Android файл MonoAndroid,Version=v1.6+.xml
<?xml version="1.0" encoding="utf-8"?>
<Framework DisplayName="Mono for Android"
Identifier="MonoAndroid"
Profile="*"
MinimumVersion="1.6"
MaximumVersion="*" />
iOS файл VSMonoTouch,Version=v1.0+.xml
<?xml version="1.0" encoding="utf-8"?>
<Framework DisplayName="VS MonoTouch"
Identifier=".NETFramework"
Profile="*"
MinimumVersion="1.0"
MaximumVersion="1.0" />
После создания этих двух файлов и перезапуска Visual Studio можно будет указывать Android и iOS в качестве поддерживаемых платформ для новых PCL-проектов или добавить эти платформы в существующие проекты через Properties -> Library -> Target Framework.
Но это еще не все нюансы.
Если вы хотите поддержку Android и iOS в PCL-проекте, то придётся отказаться от поддержки Xbox 360 и Windows Phone 7 (зато можно поддерживать Windows Phone 7.5+). Для Xbox придётся создавать еще один проект и в нем добавлять файлы из существующего PCL-проекта в виде ссылок. Или, как вариант, в одном PCL-проекте оставить все платформы от Microsoft (включая Xbox 360), а в другом оставить только iOS и Android.
Есть еще такая проблема что PCL-проект, добавленный из Visual Studio под Windows не будет участвовать в сборке решения, если открыть его в Xamarin Studio под OS X. Проект будет неактивен и будет выводиться сообщение (not built in active configuration). Решается эта проблема удалением проекта из решения и добавлением заново.
В разработке для Android актуальным является вынесение работы с файлами, базами данных, сетью и т.д., то есть с длительными операциями, в отдельный поток. В C# 5 для реализации асинхронных операций предусмотрены специальные возможности, а именно async/await [6]. К сожалению, в текущей версии Mono for Android и MonoTouch этих возможностей нет. Из-за этого многие довольно интересные библиотеки нельзя использовать в том виде, который для них предусмотрен. Например для работы с асинхронным API библиотеки sqlite-net приходится делать несколько финтов ушами. Радует то, что эти возможности должны стать доступны [7] через несколько месяцев с переходом Xamarin на C# 5.
Xamarin помимо, собственно, продажи инструментария для разработки ПО, открыли магазин [8] по продаже сторонних компонент, многие из которых действительно очень упрощают жизнь разработчику. В магазине доступны как платные, так и бесплатные библиотеки и темы оформления. Полезность, например, бесплатных Xamarin.Auth [9], Xamarin.Social [10] и Xamarin.Mobile [11] трудно переоценить. Есть возможность публиковать собственные компоненты в этом магазине.
Из проблемных моментов наиболее заметными являются:
Инструментарий от Xamarin таки да, действительно работает и если вы планируете разрабатывать несколько приложений в год или же планируемая прибыль от разрабатываемого приложения больше чем $2k, то Xamarin SDK явно может облегчить вам жизнь и избавить от двойной работы над кодом для каждой платформы.
С другой же стороны, для Indy-разработчика цена в $1k для каждой платформы мне, например, кажется чрезмерной т.к. есть много нюансов, которые необходимо знать иили прочувствовать на себе перед началом разработки, есть баги, которые неизвестно в каком режиме будут исправляться и неизвестно насколько их наличие может замедлить разработку конкретно вашего проекта.
И да. У нас заработало. В Play Store [12] и App Store [13] уже есть приложение SphereUp, разработанное с Xamarin iOS/Xamarin Android. Собственно, при разработке этого приложения и были опробованы все грабли, описанные выше.
Автор: t_rex
Источник [25]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/android-development/28997
Ссылки в тексте:
[1] обзор: http://habrahabr.ru/post/170629/
[2] попыток: http://habrahabr.ru/post/169467/
[3] здесь: http://forums.xamarin.com/discussion/1899/problem-with-deploying-apk-which-uses-android-binding-library-and-jar
[4] здесь: http://docs.xamarin.com/guides/android/advanced_topics/java_integration_overview/binding_a_java_library_(.jar)
[5] здесь: http://docs.xamarin.com/guides/ios/advanced_topics/binding_objective-c_libraries
[6] async/await: http://msdn.microsoft.com/en-us/library/vstudio/hh191443.aspx
[7] должны стать доступны: http://forums.xamarin.com/discussion/1582/could-not-load-type-iasyncstatemechine
[8] магазин: http://components.xamarin.com/
[9] Xamarin.Auth: http://components.xamarin.com/view/xamarin.auth/
[10] Xamarin.Social: http://components.xamarin.com/view/xamarin.social/
[11] Xamarin.Mobile: http://components.xamarin.com/view/xamarin.mobile/
[12] Play Store: https://play.google.com/store/apps/details?id=com.sphereup
[13] App Store: https://itunes.apple.com/app/sphereup-bgu/id558526165?mt=8
[14] Официальный блог Xamarin: http://blog.xamarin.com/
[15] Xamarin на GitHub: https://github.com/xamarin
[16] Xamarin на YouTube: http://www.youtube.com/user/XamarinHQ
[17] Для iOS: https://github.com/xamarin/monotouch-samples
[18] Для Android: https://github.com/xamarin/monodroid-samples
[19] Кроссплатформенные: https://github.com/xamarin/mobile-samples
[20] Блог Мигеля де Икаса: http://tirania.org/blog/
[21] Manski.net: http://manski.net/tags/mono-for-android/
[22] ConceptDev: http://conceptdev.blogspot.com/
[23] MonoGame: http://monogame.net/
[24] Sqlite-net на GitHub: https://github.com/praeclarum/sqlite-net
[25] Источник: http://habrahabr.ru/post/172121/
Нажмите здесь для печати.