Advertisement
  1. Code
  2. Mobile Development

Pengantar Xamarin.Forms dan SQLite

Scroll to top

Indonesian (Bahasa Indonesia) translation by Sandi Muamar (you can also view the original English article)

Di beberapa titik dalam karir mobile development Anda, Anda akan perlu untuk menangani data. Berurusan dengan data berarti lebih dari pengolahan dan menampilkan informasi kepada user akhir. Anda akan perlu untuk menyimpan informasi ini di suatu tempat dan mampu mendapatkan hal itu dengan mudah. Berkat Xamarin dan open source software, Anda dapat dengan mudah menyimpan data Anda dengan platform industri yang sudah di tes, SQLite.

1. menyimpan Data

Jadi mengapa Anda harus peduli tentang data ketika datang ke aplikasi Anda? Karena itu semua di sekitar Anda. Anda tidak dapat melarikan diri itu. Tidak peduli apa jenis app Anda buat, apakah itu game atau semacam utilitas, Anda akan perlu untuk menyimpan data di beberapa titik. Bahwa data yang di dapat bisa user dsata, statistik, atau apa pun yang menarik yang baik bagi Anda atau user akan tertarik pada beberapa titik dalam penggunaan aplikasi Anda.

Pada titik ini, mari kita asumsikan bahwa Anda telah memutuskan untuk pergi Xamarin.Forms route, karena Anda tertarik untuk menargetkan beberapa platform tidak hanya dalam logika untuk aplikasi Anda, tetapi juga untuk user interface layer.

Hebat. Tapi apa yang Anda lakukan sekarang bahwa Anda perlu untuk menyimpan informasi dalam aplikasi Anda? Jangan khawatir, ada solusi yang sangat sederhana untuk masalah ini, SQLite.

2. pengenalan SQLite

Anda sekarang melihat istilah SQLite beberapa kali dalam tutorial ini, sudah waktunya untuk turun ke daging. Apa sebenarnya itu SQLite? SQLite adalah public domain, zero configuration, transactional SQL database engine. Ini berarti adalah bahwa Anda memiliki mekanisme Terpilih penuh untuk menyimpan data Anda dengan cara yang terstruktur. Tidak hanya Anda mendapatkan semua ini, Anda juga memiliki akses ke kode sumber, karena itu merupakan open source.

Kami akan tidak mencakup semua fitur dari SQLite dalam tutorial ini hanya karena ada terlalu banyak yang harus di lalui Yakinlah bahwa Anda akan memiliki kemampuan untuk dengan mudah membuat struktur tabel untuk menyimpan data dan mengambilnya di app. Ini adalah konsep-konsep yang menjadi fokus pada dalam tutorial ini.

Dalam dunia Xamarin.Forms, SQLite secara alamai cocok untuk alasan yang sangat sederhana. engine SQLite sudah tersedia pada iOS dan Android. Ini berarti bahwa Anda dapat menggunakan teknologi ini langsung ketika Anda memilih untuk membuat sebuah aplikasi Xamarin.Forms.

Mendapatkan akses ke fungsi SQLite di Windows Phone apps memerlukan satu langkah tambahan yang kita akan pergi ke sedikit kemudian. Semua fungsi ini dan cross platform accessibility itu keren, tapi bagaimana akan kita mendapatkan akses ke implementasi ke native platform dari  C# kode di Xamarin.Forms? Dari paket NuGet bagus, itu bagaimana. Mari kita lihat.

3. menciptakan sebuah aplikasi

Mari kita mulai dengan membuat sebuah aplikasi Xamarin.Forms sederhana. Dalam tutorial ini, saya akan menggunakan Mac menjalankan Xamarin Studio, tetapi Anda dapat dengan mudah menggunakan Xamarin Studio atau Visual Studio yang berjalan pada PC.

Langkah 1: Buat sebuah proyek

Kita mulai proses dengan membuat app Xamarin.Forms baru. Untuk melakukannya, cukup pilih Mobile Apps proyek template family di sebelah kiri dan memilih salah satu template Xamarin.Forms di sebelah kanan. Anda dapat menggunakan versi PCL atau Shared dari template, tetapi untuk kasus ini, saya akan menggunakan PCL. Anda dapat mengikuti bersama menggunakan salah satu, tapi akan ada sedikit perbedaan jika Anda memilih template Shared nanti.

Anda dapat memberikan proyek nama apapun yang Anda suka. Saya akan sebut proyek ini IntroToSQLite. Setelah Anda klik tombol OK, IDE Anda akan pergi melalui proses menciptakan solusi. Solusi Anda akan berisi empat proyek:

  1. IntroToSQLite - proyek PCL
  2. IntroToSQLite.Android - proyek Android
  3. IntroToSQLite.iOS - proyek iOS
  4. IntroToSQLite.WinPhone - proyek Windows Phone (hanya pada PC)

Langkah 2: Menambahkan dukungan SQLite

Sekarang bahwa kita memiliki struktur dasar proyek kami mengatur, kita dapat mulai untuk menambahkan akses ke SQLite untuk proyek PCL kami. Kita perlu menginstal paket baru ke proyek kami bernama SQLite.Net. Ini adalah wrapper .NET sekitar SQLite yang akan memungkinkan kita untuk mengakses fungsi SQLite native dari Xamarin.Forms PCL atau Shared proyek.

Kami akses paket NuGet ini dengan mengklik kanan pada Packages atau References, tergantung pada IDE yang Anda gunakan, dan pilih Add Package (atau Reference). Dalam kotak pencarian, ketik sqlite.net. Ini akan menunjukkan Anda agak besar koleksi paket yang dapat disertakan dalam proyek Anda.

Add the SQLite NuGet packageAdd the SQLite NuGet packageAdd the SQLite NuGet package

Karena saya memilih untuk pergi PCL route untuk proyek Xamarin.Forms saya, saya akan perlu untuk memilih paket SQLite.Net PCL termasuk ke dalam proyek saya. Mana yang Anda memilih jika Anda pergi Shared project route? Tidak ada.

SQLite dan Shared Projects

Jika Anda telah memilih Shared project template sebelumnya dalam tutorial, Anda mungkin bertanya-tanya bagaimana untuk mendapatkan akses ke paket SQLite. Jawaban singkatnya adalah bahwa Anda tidak bisa. Jika Anda ingat dari tutorial sebelumnya, Anda tidak dapat menambahkan referensi ke Shared project. Untuk mendapatkan akses ke SQLite dari sebuah Shared project, Anda cukup menambahkan kode sumber untuk proyek.

Menambahkan beberapa kode

Langkah terakhir dalam menambahkan fungsionalitas SQLite untuk proyek PCL adalah untuk membuat sebuah interface yang akan memungkinkan kita akses ke dunia SQLite. Kami melakukan ini alasannya karena kita perlu mengakses fungsi native pada platform yang berbeda seperti yang kita lihat dalam tutorial sebelumnya.

Mari kita mulai dengan mendefinisikan sebuah interface yang akan memberikan kami akses ke koneksi database SQLite. Dalam proyek PCL Anda, membuat sebuah interface baru yang bernama ISQLite dan replace implementasi dengan berikut:

1
using System;
2
using SQLite.Net;
3
4
namespace IntroToSQLite
5
{
6
    public interface ISQLite
7
  {
8
		SQLiteConnection GetConnection();
9
	}
10
}

Ini adalah interface yang akan kita terapkan dan mendapatkan akses melalui DependencyService dari implementasi native.

Langkah 3: Tentukan Database

Kami sekarang memiliki akses ke fungsionalitas SQLite, mari kita menentukan database kami. Aplikasi tertentu ini akan menjadi cukup sederhana dan kami hanya akan menyimpan beberapa pikiran acak kita ketika kita datang dengan mereka.

Kita mulai dengan membuat sebuah kelas yang akan mewakili data yang disimpan dalam tabel tertentu. Mari kita sebut ini kelas RandomThought.

1
using System;
2
using SQLite.Net.Attributes;
3
4
namespace IntroToSQLite
5
{
6
    public class RandomThought
7
	{
8
		[PrimaryKey, AutoIncrement]
9
		public int ID { get; set; }
10
		public string Thought { get; set; }
11
		public DateTime CreatedOn { get; set; }
12
13
		public RandomThought ()
14
		{
15
		}
16
	}
17
}

Seperti yang Anda lihat, ini adalah kelas sangat sederhana dengan tiga properti. Dua dari properti itu adalah hanya Anda sehari-hari properti normal, Thought dan CreatedOn. Ini dua sifat akan mewakili kolom di database SQLite, yang akan berisi sebuah tabel yang bernama RandomThought. Properti yang ketiga, ID, juga akan mewakili sebuah kolom dalam tabel dan berisi id unik yang dapat kita gunakan untuk merujuk kepada RandomThought baris tertentu dalam tabel.

Hal yang menarik tentang Properti ID adalah bahwa itu dihiasi dengan dua atribut, PrimaryKey dan AutoIncrement. PrimaryKey menyuruh SQLite bahwa kolom ini akan menjadi primary key dari table, yang berarti bahwa, secara default, ia harus menjadi unik dan ada indeks diterapkan untuk itu untuk mempercepat retrievals dari tabel ini apabila merujuk kepada sebuah baris oleh kolom ini.

AutoIncrement berarti bahwa, ketika kita menyisipkan RandomThought baru ke tabel ini, kolom ID akan diisi secara otomatis dengan nilai integer tersedia berikutnya. Langkah berikutnya adalah untuk membuat tabel ini di database.

Saya ingin membuat sebuah kelas yang mewakili database saya dan memelihara semua logika untuk mengakses database dan tabel nya dalam kelas ini. Untuk ini, aku akan membuat kelas bernama RandomThoughtDatabase:

1
using System;
2
using SQLite.Net;
3
using Xamarin.Forms;
4
using System.Collections.Generic;
5
using System.Linq;
6
7
namespace IntroToSQLite
8
{
9
    public class RandomThoughtDatabase
10
	{
11
		private SQLiteConnection _connection;
12
13
		public RandomThoughtDatabase ()
14
		{
15
			_connection = DependencyService.Get<ISQLite> ().GetConnection ();
16
			_connection.CreateTable<RandomThought> ();
17
		}
18
19
		public IEnumerable<RandomThought> GetThoughts() {
20
			return (from t in _connection.Table<RandomThought> ()
21
			        select t).ToList ();
22
		}
23
24
		public RandomThought GetThought(int id) {
25
			return _connection.Table<RandomThought> ().FirstOrDefault (t => t.ID == id);
26
		}
27
28
		public void DeleteThought(int id) {
29
			_connection.Delete<RandomThought> (id);
30
		}
31
32
		public void AddThought(string thought) {
33
			var newThought = new RandomThought {
34
				Thought = thought,
35
				CreatedOn = DateTime.Now
36
			};
37
38
			_connection.Insert (newThought);
39
		}
40
	}
41
}

Ini adalah implementasi yang sangat sederhana seperti hanya berisi beberapa metode. Ini adalah biasanya beberapa operasi dasar yang Anda lakukan ketika berhadapan dengan database. Satu catatan adalah konstruktor. Dalam konstruktor kami melakukan dua hal.

Pertama, kami menggunakan kelas DependencyService untuk mendapatkan kelas terdaftar yang mengimplementasikan interface ISQLite dan memanggil metode GetConnection.

Kedua, kita menggunakan metode CreateTable pada kelas SQLiteConnection untuk membuat sebuah tabel yang disebut RandomThought. Metode ini akan membuat tabel, jika itu sudah tidak ada, dan keluar  jika sudah ada.

Jelas, Anda bisa mendapatkan canggih dengan kelas ini seperti yang Anda inginkan dengan menambahkan segala macam fungsi, tetapi operasi ini biasanya titik awal yang baik.

Langkah 4: Menambahkan iOS implementasi

Sebagian besar kode yang kita gunakan untuk berinteraksi dengan database akan ditemukan dalam proyek PCL (atau Shared). Tapi kita masih perlu melakukan sedikit wiring up dalam implementasi native untuk mendapatkan semuanya bekerja dengan benar.

Kendala utama yang kita butuhkan untuk bekerja di sekitar pada sisi asli ketika menggunakan SQLite mana kita akan menyimpan file database yang sebenarnya. Ini berbeda dari platform ke platform. Berikut adalah apa yang kita butuhkan untuk iOS.

Sebelum kita benar-benar dapat menambahkan segala macam fungsi SQLite untuk proyek iOS, kita perlu menambahkan SQLite.Net PCL serta SQLite.NET PCL - XamarinIOS Platform paket untuk proyek ini. Anda dapat mengikuti langkah yang sama yang Anda ambil di langkah 2, pastikan untuk menambahkan kedua untuk proyek. Setelah Anda menambahkan paket ini, Anda dapat mulai untuk menulis beberapa kode SQLite dalam proyek iOS.

Mari kita membuat sebuah implementasi dari interface ISQLite untuk iOS. Mulailah dengan membuat kelas baru, menamakannya SQLite_iOS.

1
using System;
2
using System.IO;
3
using SQLite;
4
using IntroToSQLite.iOS;
5
using Xamarin.Forms;
6
7
[assembly: Dependency(typeof(SQLite_iOS))]
8
9
namespace IntroToSQLite.iOS
10
{
11
    public class SQLite_iOS: ISQLite
12
	{
13
		public SQLite_iOS ()
14
		{
15
		}
16
17
		#region ISQLite implementation
18
19
		public SQLite.Net.SQLiteConnection GetConnection ()
20
		{
21
			var fileName = "RandomThought.db3";
22
			var documentsPath = Environment.GetFolderPath (Environment.SpecialFolder.Personal);
23
			var libraryPath = Path.Combine (documentsPath, "..", "Library");
24
			var path = Path.Combine (libraryPath, fileName);
25
26
			var platform = new SQLite.Net.Platform.XamarinIOS.SQLitePlatformIOS ();
27
			var connection = new SQLite.Net.SQLiteConnection (platform, path);
28
29
			return connection;
30
		}
31
32
		#endregion
33
	}
34
}
35

Kami mendapatkan akses ke lokasi yang benar untuk menyimpan database file, membuat objek SQLiteConnection baru, dan memberikannya kembali ke proyek PCL (atau Shared). Atribut assembly di bagian atas dari file yang digunakan untuk mengidentifikasi kelas ini sebagai Dependency yang dapat diperoleh melalui metode Get pada kelas DependencyService.

Langkah 5: Tambahkan implementasi Android

Langkah ini sangat mirip dengan yang sebelumnya. Satu-satunya perbedaan adalah bahwa kode akan berubah sedikit karena fakta bahwa lokasi database file akan berbeda. Anda masih perlu menambahkan paket yang tidak tepat untuk proyek Android (SQLite.Net PCL dan SQLite.NET PCL - XamarinAndroid) seperti yang Anda lakukan sebelumnya. Setelah Anda menyelesaikan, Anda dapat menambahkan kode yang sesuai dalam kelas baru bernama SQLite_Android.

1
using System;
2
using System.IO;
3
using Xamarin.Forms;
4
using IntroToSQLite.Android;
5
6
[assembly: Dependency(typeof(SQLite_Android))]
7
8
namespace IntroToSQLite.Android
9
{
10
    public class SQLite_Android: ISQLite
11
	{
12
		public SQLite_Android ()
13
		{
14
		}
15
16
		#region ISQLite implementation
17
18
		public SQLite.Net.SQLiteConnection GetConnection ()
19
		{
20
			var fileName = "RandomThought.db3";
21
			var documentsPath = Environment.GetFolderPath (Environment.SpecialFolder.Personal);
22
			var path = Path.Combine (documentsPath, fileName);
23
24
			var platform = new SQLite.Net.Platform.XamarinAndroid.SQLitePlatformAndroid ();
25
			var connection = new SQLite.Net.SQLiteConnection (platform, path);
26
27
			return connection;
28
		}
29
30
		#endregion
31
	}
32
}
33

Anda sekarang memiliki implementasi ISQLite interface yang bekerja dari perspektif Android app.

Langkah 6: Menambahkan Windows Phone implementasi

Karena saya menjalankan aplikasi ini dari Mac, saya tidak akan membuat implementasi Windows Phone, tetapi jika Anda ingin melakukan ini, Anda bisa.

Langkah pertama adalah untuk menambahkan dukungan untuk proyek Windows Phone Anda untuk SQLite. Seperti disebutkan sebelumnya, SQLite datang secara default pada iOS dan Android. Hal ini tidak benar untuk Windows Phone, tetapi didukung. Untuk mendapatkannya, Anda dapat mengikuti petunjuk yang terdapat dalam situs web Xamarin.

Setelah menginstal SQLite, proses penambahan fungsi untuk Windows Phone akan hampir persis sama, kecuali bahwa paket untuk menginstal SQLite.Net PCL dan SQLite.Net PCL - WindowsPhone 8 Platform. Paket-paket ini diinstal, Anda dapat membuat Windows Phone implementasi ISQLite.

1
using System;
2
using System.IO;
3
using Xamarin.Forms;
4
using IntroToSQLite.WinPhone;
5
6
[assembly: Dependency(typeof(SQLite_WinPhone)]
7
8
namespace IntroToSQLite.WinPhone
9
{
10
    public class SQLite_WinPhone: ISQLite
11
    {
12
		public SQLite_WinPhone ()
13
		{
14
		}
15
16
		#region ISQLite implementation
17
18
		public SQLite.Net.SQLiteConnection GetConnection ()
19
		{
20
			var fileName = "RandomThought.db3";
21
			var path = Path.Combine (ApplicationData.Current.LocalFolder.Path, fileName);
22
23
			var platform = new SQLite.Net.Platform.WindowsPhone8.SQLitePlatformWP8 ();
24
			var connection = new SQLite.Net.SQLiteConnection (platform, path);
25
26
			return connection;
27
		}
28
29
		#endregion
30
	}
31
}
32

Di sana Anda memilikinya. Sekarang Anda memiliki semua native implementasi. Saatnya untuk memberikan aplikasi ini sebuah interface pengguna dan mendapatkan data ke dalam database.

Langkah 7: Menambahkan User Interface

Karena tutorial ini juga menjadi topik Xamarin.Forms, aku akan menganggap bahwa Anda setidaknya memiliki pengetahuan dasar dari Xamarin.Forms. Dengan asumsi ini dalam pikiran, aku tidak akan pergi ke banyak detail pada proses pepmbuatan user interface. Jika Anda memerlukan informasi latar belakang lebih lanjut tentang Xamarin.Forms, memeriksa Tutorial Xamarin.Forms saya yang lain pada Tuts +.

User interface akan terdiri dari dua halaman yang terpisah. Halaman pertama akan berisi daftar semua pikiran kita telah masuk dalam daftar sementara halaman kedua akan membiarkan user memasukkan pemikiran baru. Mari kita membangun halaman-halaman ini.

Membuat ListView

Kita pertama akan berfokus pada membuat halaman pertama yang akan berisi daftar objek RandomThought. Mulailah dengan membuat file baru dalam proyek PCL (atau Shared) dan nama itu RandomThoughtsPage. Ganti default implementasi dengan berikut:

1
using System;
2
using Xamarin.Forms;
3
4
namespace IntroToSQLite
5
{
6
    public class RandomThoughtsPage: ContentPage {
7
		private RandomThoughtDatabase _database;
8
		private ListView _thoughtList;
9
10
		public RandomThoughtsPage (RandomThoughtDatabase database)
11
		{
12
			_database = database;
13
			Title = "Random Thoughts";
14
			var thoughts = _database.GetThoughts ();
15
16
			_thoughtList = new ListView ();
17
			_thoughtList.ItemsSource = thoughts;
18
			_thoughtList.ItemTemplate = new DataTemplate (typeof(TextCell));
19
			_thoughtList.ItemTemplate.SetBinding (TextCell.TextProperty, "Thought");
20
			_thoughtList.ItemTemplate.SetBinding (TextCell.DetailProperty, "CreatedOn");
21
22
			var toolbarItem = new ToolbarItem {
23
				Name = "Add",
24
				Command = new Command(() => Navigation.PushAsync(new ThoughtEntryPage(this, database)))
25
			};
26
27
			ToolbarItems.Add (toolbarItem);
28
29
			Content = _thoughtList;
30
		}
31
32
		public void Refresh() {
33
			_thoughtList.ItemsSource = _database.GetThoughts ();
34
		}
35
	}
36
}
37

Sebagian besar pekerjaan yang dilakukan di kelas ini adalah dalam konstruktor. Konstruktor memungkinkan kita untuk pass instance RandomThoughtsDatabase untuk mendapatkan semua pikiran disimpan. Kami mengatur properti Title halaman untuk "Random Thoughts", mengambil semua pikiran yang ada, membuat sebuah instance baru dari ListView, dan membuat ToolbarItem yang akan memungkinkan kita untuk klik tombol untuk membuka halaman entry. Kami belum meng-implemntasikannya, tapi kami akan segera.

Untuk mendapaktan RandomThoughtsPage baru kami pada layar, kita perlu untuk membuat sedikit modifikasi App.cs file. Dalam file ini, mengubah metode GetMainPage terlihat seperti berikut:

1
public static Page GetMainPage ()
2
{ 
3
    var database = new RandomThoughtDatabase ();
4
5
    return new NavigationPage (new RandomThoughtsPage (database));
6
}

Metode GetMainPage sekarang membuat sebuah instance baru dari kelas RandomThoughtDatabase kami dan mengembalikan sebuah instance baru dari RandomThoughtsPage. Dengan perubahan ini, iOS dan Android apps akan terlihat seperti ini:

Random Thoughts page for iOSRandom Thoughts page for iOSRandom Thoughts page for iOS
Random Thoughts page for AndroidRandom Thoughts page for AndroidRandom Thoughts page for Android

Membuat halaman entri

Kami sekarang memiliki halaman daftar untuk semua objek RandomThought, tapi kami tidak punya cara untuk memasuki yang baru. Untuk itu, kita akan membuat halaman lain serupa ke halaman sebelumnya. Buat sebuah file baru dalam proyek PCL (atau Shared) dan diberi nama ThoughtEntryPage. Ganti default implementasi dengan berikut:

1
using System;
2
using Xamarin.Forms;
3
4
namespace IntroToSQLite
5
{
6
    public class ThoughtEntryPage: ContentPage {
7
		private RandomThoughtsPage _parent;
8
		private RandomThoughtDatabase _database;
9
10
		public ThoughtEntryPage ( RandomThoughtsPage parent, RandomThoughtDatabase database)
11
		{
12
			_parent = parent;
13
			_database = database;
14
			Title = "Enter a Thought";
15
16
			var entry = new Entry ();
17
			var button = new Button {
18
				Text = "Add"
19
			};
20
21
			button.Clicked += async (object sender, EventArgs e) => {
22
				var thought = entry.Text;
23
24
				_database.AddThought(thought);
25
26
				await Navigation.PopAsync();
27
28
29
				_parent.Refresh();
30
			};
31
32
			Content = new StackLayout {
33
				Spacing = 20,
34
				Padding = new Thickness(20),
35
				Children = { entry, button },
36
			};
37
		}
38
	}
39
}
40

Dalam kelas ini, Semua pekerjaan dilakukan dalam konstruktor. Kami mendapatkan referensi ke halaman induk, RandomThoughtsPage, serta database. Sisanya adalah konfigurasi dasar kode dengan objek Entry untuk memasukkan teks dan Button.

Setelah pengguna menyentuh Button, kami menggunakan database untuk menambahkan pemikiran baru, mengabaikan halaman, kembali ke halaman daftar, dan memanggil metode Refresh untuk memperbarui ListView. Setelah ini semua sudah di wired up, kita dapat menjalankan untuk benar-benar memasukkan beberapa nilai.

Memesukan pikiran

Berikut adalah apa yang tampak seperti pada iOS dan Android untuk memasukkan beberapa pikiran Anda:

Adding thoughts on iOSAdding thoughts on iOSAdding thoughts on iOS
Adding thoughts on AndroidAdding thoughts on AndroidAdding thoughts on Android

Melihat daftar

Setelah Anda memasukkan beberapa pemikiran, daftar Anda akan terlihat seperti ini:

Listing thoughts on iOSListing thoughts on iOSListing thoughts on iOS
Listing thoughts on AndroidListing thoughts on AndroidListing thoughts on Android

Kesimpulan

Di sana Anda memilikinya. Anda sekarang memiliki kemampuan untuk menambahkan fungsi database untuk aplikasi Xamarin.Forms Anda untuk menyimpan dan mengambil apapun data dengan mudah.

Untuk melanjutkan perjalanan belajar Anda dengan Xamarin.Forms dan SQLite, saya memberikan tantangan berikut. Lihat jika Anda dapat meningkatkan aplikasi ini untuk mengaktifkan menghapus pikiran dan memperbarui halaman daftar dengan cara yang sama sebagai halaman entri. Good luck dan happy coding.

Advertisement
Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.