Это будет практическое руководство по использованию SQLite в Unity3d. Я расскажу что это такое, для чего может потребоваться, как реализовать и порекомендую инструменты для удобной работы. Статья ориентирована на начальный и средний уровни. В конце Вас ждёт небольшой бонус. Всем заинтересованным добро пожаловать под кат.
Что это?
SQLite это легковесная, встраиваемая и абсолютно самодостаточная реляционная база данных. Она является самой распространённой SQL-базой данных, по миру насчитывается не менее 500 млн. установок, это по сравнению со 100 млн. деплоев остальных SQL-баз данных. Используется в таких проектах, как Mozilla Firefox, Chrome, Skype, Windows Phone 8, iOS, Android, Symbian и прочие, и прочие… И самое главное она бесплатна, с открытым исходным кодом, а также имеет 100% покрытие тестами. Обо всём этом вы можете узнать на официальном сайте SQLite и в постах на хабре.
Зачем?
Отмечу, что в нашем небольшом отделе почти у всех стоят разные ОС, и поскольку для нас важна взаимозаменяемость, мы старались выбирать кроссплатформенные решения.
Для нас SQLite был хорошим вариантом для хранения внешней информации — ресурсов, конфигурационных настроек, локализации. От внешних xml-подобных файлов мы отказались сразу, из-за проблем с переносом на разные устройства, раздутости и медленности. Целесообразность использования SQLite для Вашего проекта можно посмотреть здесь.
Как?
Для создания и редактирования БД наш выбор пал на SQLite Manager — это плагин для Firefox, он бесплатный, удобный и кроссплатформенный. Единственное, что мне не понравилось — это приходилось дописывать SQL запрос на создание таблицы для добавления внешних ключей, а также невозможность редактирования записей в составленном VIEW из нескольких таблиц. А в остальном всё очень наглядно. Можно даже экспериментировать с SQL запросами к вашей БД. На выходе вы получаете один файлик, расширение которого можете указать сами (.db, .sqlite, .bytes и пр.), но Unity понимает только «.bytes».
Ещё один важный момент. Размещение в БД бинарников по типу картинок, музыки, видео является плохой практикой. Грубо говоря, всё что весит более 100 kb должно находиться в локальной папке, а в БД вы прописываете только пути. Иначе скорость чтения бинарника из базы становится больше, чем его загрузка локально.
Пришло время теперь разместить это всё в нашем Unity проекте. Для использования SQLite качаем библиотеки sqlite.dll (для Win, iOS и MacOS) и sqlite.os (для Android). Размещаем библиотеки здесь — Assets/Plugins/sqlite.dll
и Assets/Plugins/Android/sqlite.so
. Ежели папочки Plugins
нет, то создаём её. Созданную БД (назовём её к примеру db.bytes
) кладём в папочку Assets/StreamingAssets
(создаём, если отсутствует). В итоге после деплоя, наша база окажется здесь:
Win и Mac OS:
Application.dataPath + "/StreamingAssets/db.bytes"
iOS:
Application.dataPath + "/Raw/db.bytes"
а вот на Android будет упакована в apk файл приложения:
"jar:file://" + Application.dataPath + "!/assets/db.bytes".
Вам потребуется используя WWW класс, чтобы загрузить базу, а затем скопировать в папку Application.persistentDataPath + "/"
.
Но эти директории обладают только правами для чтения (кроме Android'a), если же вам потребуется записать что-либо в базу, её необходимо переместить сюда:
Win и Mac OS:
Application.dataPath + "/db.bytes"
iOS:
string path = Application.dataPath.Substring(0, Application.dataPath.LastIndexOf("/"));
path = path.Substring(0, path.LastIndexOf("/")) + "/Documents/db.bytes";
или так
string path = Application.dataPath.Substring(0, Application.dataPath.length - 5);
path = path.Substring(0, path.LastIndexOf("/")) + "/Documents/db.bytes";
или так
string path = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal) + "/db.bytes";
Про Android написано выше.
Затем подключаем пакет System.IO и пишем
File.Copy(openPath, savePath);
для Android'a соответственно
WWW www = new WWW(openPath);
while(!www .isDone) {} // тут очень внимательно, используйте корутины
File.WriteAllBytes(savePath, www.bytes);
Ну и бинарники ресурсов: модели, видео, музыка и т. д. кладём в папочку Assets/Resources/
. После билда они упаковываются в бинарник resources.assets
. А в приложении мы загружаем их — Resources.Load(String path). Ну например, мы положили звук в папочку Assets/Resources/Sounds/sound1.mp3
, в базе у нас такая запись Sounds/sound1.mp3
, и в приложении это будет выглядеть так
AudioClip a = Resources.Load("Sounds/sound1.mp3") as AudioClip;
Теперь настало время считать данные из нашей базы данных. Не люблю я писать SQL запросы и парсить сырые данные в объекты, поэтому специально для SQLite мы нашли opensource проект SQLite-net ORM, это библиотека объёктно-реляционного отображения. Это технология, которая связывает базу данных с концепциями объектно-ориентированного программирования. Здесь есть поддержка Linq, например, можно сделать выборку:
public class Favorite
{
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
public int UserId { get; set; }
public string Url { get; set; }
}
public Favorite[] GetFavorites(SQLiteConnection c, int id)
{
var q = from f in c.Table<Favorite>()
where f.UserId == id
select f;
return q.ToArray();
}
или редактировать:
public void AddFavorite(SQLiteConnection c, string url, int id)
{
var fav = new Favorite()
{
UserId = id,
Url = url
};
c.Insert(fav);
}
Но Linq поддерживается не в полном объёме, например, не поддерживается JOIN, поэтому для сложных запросов придётся всё-таки писать SQL код.
Где мой бонус?
Ну в принципе самое главное я написал. Теперь обещанный бонус. Предлагаю вам опробовать SQLite в своём проекте, для решения задачи локализации.
Имеем базу данных:
Для просмотра, редактирования и создания мы разработали специальную тулзу для локализаторов, которую я тоже выкладываю (Adobe Air build для Win и Mac OS): cсылка. Дерзайте!
Спасибо за внимание, жду ваших отзывов.
Автор: ierostenko