シルバーウィークにXamarin.FormsでFacebookアプリを作成した
1.#6 JXUGC
10月3日、「第6回 Japan Xamarin User Group Conference 東京 事例スペシャル!」に参加させて頂きました。
第6回 Japan Xamarin User Group Conference 東京 - connpass
また、お時間を少し頂戴し、タイトルのお話しをさせて頂きました。
2.事例スペシャル
当初から、主催の田淵さん(@ytabuchi)に登壇のお誘いを頂いていたのですが、仕事柄、「お話しできるような ”事例” が無い」ということでお断りさせて頂きました。
しかし、いつまでたってもセッション枠は消えず、タイトル空欄の私の行が残っているので・・・いよいよ焦って事例を作ることにしましたw
そういう意味で、火がついたのは、約2週間前です・・・
丁度シルバーウィークで、まとまった時間が取れるので、「Xamarin.Formsを使用して短期間でどれぐらい作れるか」というコンセプトで作業してみました。
3.Facebookアプリ
時間も制限があるので、今回は、以前作成したことのあるWebアプリをネイティブアプリにリニューアルすることにしました。
結果的には、FacebookのAPIの仕様が当時から比べて結構変わっており、内容はかなり違ったものになってしまいました。
「仕様どおり」ではなく、「時間どおり」です^^)
※V2.1以降、FQLは非推奨 scopeについてもだいぶ変わってました。
4.結論
内容については、スライドを見て頂きたいのですが・・・ここでは、結論だけ。
あくまで、個人的な感想ですが・・・
- Xamarin.Formsを使用すると、短期間で結構動くものが作れる。(しかも、iOS,Android,WindowPhone対応)
- 細かいところに、気が付きすぎると、作業量が大きく膨らむ(予感がする。)
という事で、
「Xamarin.Formsは、頑張りすぎないのが吉」
って事で。
※ぜんぜん、disっている訳ではありません。
Xamarin.FormsでAzureモバイルサービスによるToDoアプリを作成するには?
BuildInsiderで連載されている「Xamarin逆引きTips」に寄稿させて頂きました。
Xamarin.FormsでAzureモバイルサービスによるToDoアプリを作成するには? - Build Insider
使用したコードは、下記にあります。github.com
Xamarin.Formsでプラットフォームごとの微調整を行うには?
BuildInsiderで連載されている「Xamarin逆引きTips」に寄稿させて頂きました。
Xamarin.Formsでプラットフォームごとの微調整を行うには? - Build Insider
使用したコードは、下記にあります。
Xamarin.Forms PCLでのファイルIO ( PCL Storageを使用する )
1. PCL Storage
Xamarin.FormsのPCLでファイルのIOを書こうとしたとき、System.IOに File や Directory が無くて固まった経験はないでしょうか?もともと、ファイルの扱いはプラットフォーム固有なので、当然といえば当然なのですが・・・
しかし、Xamarin.iOSやXamarni.Androidでは、ちゃんと、System.IO.FileやSystem.IO.Directoryが使えるので、それをラッパーすればいいだけです。
フォルダのパスがプラットフォーム固有になるので、そこだけ気を付ければいいって事でしょうか。
と言いながら、いろいろ検索していると、コンポーネントストアに「PCL Storage」なるものを見つけました。
2. インストール
同プログラムは、CodePlexやGithubでコードも公開されています。
また、NuGetでのインストールも可能です。
コンソールでも可能ですが、今回は、「NnuGetパッケージの管理」から行いました。
※実は、ComponentsというフォルダがiOSとAndroidのプロジェクトにしかなく、PCLプロジェクトが無かったので、右クリックでの導入要領が分かりませんでした・・・
全プロジェクトにインストールされます。
3. 動作確認
次のようなサンプルを書いて、動作確認してみました。
EntryコントロールとButtonコントロールを配置し、ボタンを押すと、Entryコントロールの内容をファイルに書き込むものです。
//App.cs using PCLStorage; using Xamarin.Forms; namespace PCLStorageSample { public class App : Application { public App() { MainPage = new MyPage(); } } internal class MyPage : ContentPage { public MyPage() { var entry = new Entry(); var button = new Button() { Text = "OK", Command = new Command(async () => { // ルートフォルダの取得 var folder = FileSystem.Current.LocalStorage; // フォルダの作成 var subFolder = await folder.CreateFolderAsync("SubFolder", CreationCollisionOption.OpenIfExists); // フォルダの作成 var file = await subFolder.CreateFileAsync("Text.txt", CreationCollisionOption.ReplaceExisting); // Entryコントロール尾内容をの書き込む await file.WriteAllTextAsync(entry.Text); // ファイルの内容を読み込む var str = await file.ReadAllTextAsync(); str = ""; }) }; Content = new StackLayout{ Padding = new Thickness(0,Device.OnPlatform(20,0,0),0,0), Children = { entry,button } }; } } }
(1) iOS
上記のコードを実行すると、下記のような画面になります。Entryコントロールに「test-message」と入力して、OKボタンを押し、ファイルのIOを行ったところでブレークポイントで止めて、内容を確認してみました。
ファイルから読み込んだ内容が、書き込んだものと同じになっているのが、確認できます。
また、この時の、各オブジェクトの状況は次のようになっています。
PCLStorage.IFolder folder のパスは、「/User/username/Library/developer/CoreSimulator/Data/Application/A3297...C370/Document/..Library」となっており、そのサブフォルダ「SubFolder」とその中の
ファイル「Text.txt」が見て取れます。
※これは、シュミレータでの動作ですが、実機では「/var/mobile/Containers/Data/Application/53B38A17-AC94-49C9-A3E7-21A2B08F5706/Documents/../Library」のようになっています。
(2) Android
Androidでは、次のようになります。Entryコントロールに「test-android」と入力して、iOSと同じ要領で確認してみました。
今度は、PCLStorage.IFolder folder のパスが「/data/data/PCLStorageSample.Droid/files」となっているのが確認できます。
(3) WindowsPhone
最後に、WindowsPhoneです。こちらの、PCLStorage.IFolder folder は、「/data/data/PCLStorageSample.Droid/files」です。
4. ルートフォルダ
念のため、各プラットフォームごとのルートフォルダの取得について、Githubからコードを確認しておきます。https://github.com/dsplaisted/PCLStorage/blob/master/src/PCLStorage.FileSystem.Desktop/DesktopFileSystem.cs
public IFolder LocalStorage{ get{ // SpecialFolder.LocalApplicationData is not app-specific, so use the Windows Forms API to get the app data path //var localAppData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); #if ANDROID var localAppData = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); #elif IOS var documents = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); var localAppData = Path.Combine(documents, "..", "Library"); #else var localAppData = System.Windows.Forms.Application.LocalUserAppDataPath; #endif return new FileSystemFolder(localAppData); } }
コードを確認すると、Android、iOS、WindowsPhoneについては、ルートフォルダの取得以外やパスの扱いいがは、ほとんど共通のようです。
しかし、何と言っても、パッケージインストールだけで簡単に使えてしまう魅力は捨てがたいです。
Xamarin.Forms Mobile AppでToDoアプリを作成する(その1)
1. モバイルサービスからMobile Appsへ
Microsoft Azureの新ポータル(2015年4月28日時点でPREVIEW版)では、従来の「モバイルサービス」が「Mobile Apps」となっています。今回は、ちょっと気が早い?かも知れませんが・・・
新ポータルの綺麗な画面に誘われて、Xamarin.Formsで使ってみました。
現(PREVIEW)時点で・・・
・「モバイルサービス」で作成したものは、Mobile Appsから見えません・・・
・「モバイルサービス」では、サーバ側の処理をnodejsと.NETの2種類から選択できましたが、「Mobile Apps」では、.NETのみです。
・一応、モバイルサービスも残るみたいです。
「Mobile Services continue to be available as a standalone service and remain fully supported.」
http://azure.microsoft.com/en-us/documentation/articles/app-service-changes-existing-services/
2. Mobile Appの作成
以下、Mobile Appを作成する手順です。
(1)新ポータルでは、すべてのサービスは左下の(+新規)から行います。
(2)展開したウインドウから「Web + Mobile」>「Mobile App」と選択し「Name」の所にサービス名(ここでは「AzureToDoSample」とした)を入力します。
(3)続いてデータベースの設定を行います。
「PACKAGE SETTING」>「USERDATABASE」>「新しいデータベースの作成」を選択します。
ここで、「新しいデータベースの作成」ではなく「既存のデータベースの使用」を選択した場合、この先のDB関連の指定は必要なくなります。
(4)「名前」の所にデータベースの名前を入力し、「サーバー名」「サーバ管理者ログイン」「パスワード」を入力して「OK」「OK」で閉じていきます。
(5)設定が終わったら「作成」ボタンを押します。
(6)作成中の表示が出ますので、しばらく待ちます。(1分ぐらい?)
(7)出来上がると、作成したサービスを設定する画面になります。
ここで、「Add Client」を選択します。
(8)「Xamarin.Android」を選択し、「CREATE A NEW APP」で「DOWNLOAD」を押してひな形となるテンプレートをダウンロードします。
実は、Xamarin.Formsでプログラムを書く場合、テンプレートから使用するのは、サーバ側のMVCプロジェクトだけなので、「Windows(C#)」でも「Xamarin.iOS」でも、何をダウンロードしても関係ありませんw
(9)ダウンロードした、テンプレートは次のようになっています。
3. Xamarin.Formsプロジェクトの作成
(1)VisualStudioで開いてみると、Xamarin.Android用のプロジェクト「AzureToDoSample」と、サーバ側のMVCプロジェクト「AzureToDoSampleService」の2つが含まれているのを確認することができます。(2)Xamarin.Android用のプロジェクトは要らないので、ばっさり削除します。
※実はXamarin.Android用のコードは、Xamarin.Formsでも利用可能なものが多いので、適当にフォルダ名を変えて置いておくと、色々吉です。
(3)続いて、このソリューションにXamarinFormsのプロジェクトを追加します。
ここでは、プロジェクト名を「AzureToDoSample」としました。
(4)プロジェクトの追加後、ソリューションに5つのプロジェクトが確認できます。(追加されたのは4つ)
AzureToDoSample(移植可能) : クラアントPCLプロジェクト
AzureToDoSample.Droid :Androidクラアントプロジェクト
AzureToDoSample.iOS :iOSクラアントプロジェクト
AzureToDoSample.WinPhone :WindowsPhone クラアントプロジェクト
AzureToDoSampleService :サーバ用MVCプロジェクト(これは、削除しないで残ったテンプレートのプロジェクト)
4. サーバ側MVCプロジェクトのコンパイルと登録
当初、サーバ側の構築を行います。(1)コンパイルの後、ソリューションエクスプローラでMVCプロジェクト「AzureToDoSampleService」を右クリックして「登録」を選択します。
(2)「Microsoft Azure Websites」を選択します。
(3)「既存のWebサイト」で、作成したサービスが選択できます。
サーバから検索するためには、Microsoftアカウントにサイインしている必要があります。
(4)「サーバー」「ユーザ名」「パスワード」など、全てがインポートされるので「発行」ボタンを押すだけです。
すいません、まだXamarin.Forms書いてませんが・・・
つづく・・・
5. 参考にさせて頂いたページ
Azure Mobile Apps と Mobile Services の違いについて - nnasakiのブログ
Azure App Service | ブチザッキ
Xamarin.Forms ローカルデータベース(SQLite)の利用
1. ローカルデータベース
Xamarin.Formsでは、SQLite.Netを使用することで、簡単にローカルのSQLiteデータベースが利用可能です。
今回は、このSQLite.NetをPCLで実装する方法について紹介します。
PCLで、このSQLite.Netを利用する場合、プラットフォーム固有の部分(最初の初期化)だけを、DependencyServiceで記述し、それ以外をPCLで実装する形になります。
※プラットフォーム固有の部分とは、主にデータファイルの場所を取得するあたりです。
※Xamarinのページでは、「Portable」と「Sharde」の2種類の実装方法が紹介されています。
2. NuGetパッケージのインストール
SQLite.NetはNuGetパッケージで簡単に利用が可能になっています。
「NuGet パッケージの管理」で 'SQLite.Net.PCL' で検索できます。
最初、うまく「SQLite.Net.Platform.Xamarin(Pratform)」が入らないな・・・と試行錯誤していたら、急にうまく行くようになって、よく見たら最終発行日が昨日になっていたw(途中で更新されたのですね)
※WindowsPhoneの場合は、'SQLite.Net-PCL'の他に依存関係から'sqlite-net-wp8 3.8.5'もインストールされます。
3. インターフェースの定義
プラットフォーム固有の部分をDependencyServiceで記述するためのインターフェースを定義します。
PCLプロジェクトにISQLite.csを追加しました。
これは、SQLiteを初期化して、SQLiteConnectionのインスタンスを取得するものです。
//ISQLite.cs using SQLite.Net; namespace SQLiteSample{ public interface ISQLite{ SQLiteConnection GetConnection(); } }
なお、このインターフェースの利用例は、次のようになります。
db = DependencyService.Get<ISQLite> ().GetConnection (); db.CreateTable<T>();
4. 各プラットフォームの実装
DependencyService用に定義されたインターフェースを各プラットフォームで実装します。iOS
iOSプロジェクトにSQLite_iOS.csを追加しました。using System; using System.IO; using SQLite.Net; using SQLite.Net.Platform.XamarinIOS; using SQLiteSample.iOS; using Xamarin.Forms; [assembly: Dependency(typeof(SQLite_iOS))] namespace SQLiteSample.iOS{ public class SQLite_iOS : ISQLite{ public SQLiteConnection GetConnection(){ const string sqliteFilename = "TodoSQLite.db3"; //データベース名 var documentsPath = Environment.GetFolderPath(Environment.SpecialFolder.Personal); //Documentsフ ォルダ var libraryPath = Path.Combine(documentsPath, "..", "Library"); // ライブラリフォルダ var path = Path.Combine(libraryPath, sqliteFilename);//DBファイルのパス var plat = new SQLitePlatformIOS(); var conn = new SQLiteConnection(plat, path); return conn; } } }
Android
AndroidプロジェクトにSQLite_Droid.csを追加しました。
using System.IO; using SQLiteSample.Droid; using Xamarin.Forms; [assembly: Dependency(typeof(SQLite_Android))] namespace SQLiteSample.Droid{ public class SQLite_Android : ISQLite{ public SQLite.Net.SQLiteConnection GetConnection() { const string sqliteFilename = "TodoSQLite.db3"; //データベース名 var documentsPath = System.Environment.GetFolderPath (System.Environment.SpecialFolder.Personal);//Documentsフォルダ var path = Path.Combine(documentsPath, sqliteFilename);//DBファイルのパス var plat = new SQLite.Net.Platform.XamarinAndroid.SQLitePlatformAndroid(); var conn = new SQLite.Net.SQLiteConnection(plat, path); return conn; } } }
WindowsPhone
WindowsPhoneプロジェクトにSQLite_WinPhone.csを追加しました。
using System.IO; using Windows.Storage; using SQLite.Net; using SQLite.Net.Platform.WindowsPhone8; using SQLiteSample.WinPhone; using Xamarin.Forms; [assembly: Dependency(typeof(SQLite_WinPhone))] namespace SQLiteSample.WinPhone { public class SQLite_WinPhone : ISQLite{ public SQLiteConnection GetConnection(){ const string sqliteFilename = "TodoSQLite.db3";//データベース名 var path = Path.Combine(ApplicationData.Current.LocalFolder.Path, sqliteFilename);//DBファイルの パス var plat = new SQLitePlatformWP8(); var conn = new SQLiteConnection(plat, path); return conn; } } }
5. データクラスとデータベースへのアクセスクラスの作成
データクラス
本サンプルのデータクラスとして、PCLプロジェクトにTodoItem.csを追加しました。キーとなるIDのほかに、文字列を保存するText、作成日時のCreatedAt、そして、削除状態を表現するDeleteです。
using System; using SQLite.Net.Attributes; namespace SQLiteSample{ public class TodoItem{ [PrimaryKey, AutoIncrement] public int ID { get; set; } public string Text { get; set; } public DateTime CreatedAt { get; set; }//作成日時 public bool Delete { get; set; }//削除フラグ(trueの時、表示しない) } }
データベースへのアクセスクラス
データベースへのアクセスのための、PCLにTodoRepository.csを定義します。
実装したのは、一覧取得と、データの追加・更新だけです。
using System.Collections.Generic; using SQLite.Net; using Xamarin.Forms; namespace SQLiteSample{ class TodoRepository{ static readonly object Locker = new object(); readonly SQLiteConnection _db; public TodoRepository(){ _db = DependencyService.Get<ISQLite> ().GetConnection ();//データベース接続 _db.CreateTable<TodoItem>();//テーブル作成 } //一覧 public IEnumerable<TodoItem> GetItems(){ lock (Locker){ //Delete==falseの一覧を取得する(削除フラグが立っているものは対象外) return _db.Table<TodoItem>().Where(m => m.Delete == false); } } //更新・追加 public int SaveItem(TodoItem item){ lock (Locker){ if (item.ID != 0){//IDが0で無い場合は、更新 _db.Update(item); return item.ID; } return _db.Insert(item);//追加 } } } }
6. 画面実装とデータベースの利用
以上で、段取りは整ったので、画面とDBアクセスを実装します。
Addボタンで追加、リストのタップで削除になってます。
using System; using Xamarin.Forms; namespace SQLiteSample{ public class App : Application{ public App(){ MainPage = new MyPage(); } protected override void OnStart(){} protected override void OnSleep(){} protected override void OnResume(){} } class MyPage : ContentPage{ readonly TodoRepository _db = new TodoRepository(); public MyPage(){ //データ表示用リストボックス var listView = new ListView{ ItemsSource = _db.GetItems(), ItemTemplate = new DataTemplate(typeof(TextCell)) }; listView.ItemTemplate.SetBinding(TextCell.TextProperty, "Text"); listView.ItemTemplate.SetBinding(TextCell.DetailProperty, new Binding("CreatedAt", stringFormat: "{0:yyy/MM/dd hh:mm}")); listView.ItemTapped += async (s, a) =>{//リストがタップされた時の処理 var item = (TodoItem)a.Item; if (await DisplayAlert("削除してい宜しいですか", item.Text, "OK", "キャンセル")){ item.Delete = true;//削除フラグを有効にして _db.SaveItem(item);//DB更新 listView.ItemsSource = _db.GetItems();//リスト更新 } }; //文字列入力 var entry = new Entry{ HorizontalOptions = LayoutOptions.FillAndExpand }; //追加ボタン var buttonAdd = new Button{ WidthRequest = 60, TextColor = Color.White, Text = "Add" }; buttonAdd.Clicked += (s, a) =>{//追加ボタンが押された時の処理 if (!String.IsNullOrEmpty(entry.Text)){//Entryに文字列が入力されている場合に処理する var item = new TodoItem { Text = entry.Text, CreatedAt = DateTime.Now, Delete = false }; _db.SaveItem(item); listView.ItemsSource = _db.GetItems();//リスト更新 entry.Text = ""; } }; Content = new StackLayout{ Padding = new Thickness(0, Device.OnPlatform(20, 0, 0), 0, 0), Children = { new StackLayout { BackgroundColor = Color.Navy,//入力部の背景色はネイビー Padding = 5, Orientation = StackOrientation.Horizontal, Children = {entry, buttonAdd}//Entryコントロールとボタンコントロールを横に並べる }, listView//その下にリストボックスを置く } }; } } }
実行画面は次のとおりです。
7. WindowsPhoneの場合
以上で、Xamarin.FormsからSQLite.Netを利用する手順は終了なのですが・・・
WindowsPhoneは、デフォルトでSQLite自体がインストールされていないので、初めてのSQLiteを使用する場合は、このライブラリ自体をインストールする必要があります。そして、アプリ作成時は、このライブラリを参照に追加することになります。
以下、手順を追って説明します。
(1)ダウンロード
http://www.sqlite.org/download.html#wp8から、WindowsPhone8用のものをダウンロードします。(2)インストール
ダウンロードした、vsixファイルを実行して、インストールします。(3)VisualStudio再起動
参照の一覧に表示するためにVisualStudioの再起動が必要です。(4)参照追加
WindowsPhoneプロジェクトの参照の追加で「SQLite for Windows Phone」を追加します。8. 参考にさせて頂いたページ
Xamarin.AndroidでSQLiteを使う - かずきのBlog@hatena
Working with a Local Database - Xamarin
↓サンプルはここに置きました。github.com