Mono と F# を CentOS/Debian 上でビルドしている途中

なぜか、現状の Raspberry Pi 上では

という状態で、このテストエラーは Xamarin Bug  https://bugzilla.xamarin.com/show_bug.cgi?id=17654 を見ると直っているらしい。この現象自体は Mono 3.2.7 で発生しているので、手元の Mono 3.2.8 は大丈夫なはずなんだけど、同じようにダメ。おそらく RasPi にあるレポジトリが何らかのタイミングで古いのではないか?と思のだが…これを、RasPi 上でビルドするとえらい時間がかかる。6時間かかってもまだ Mono のビルドが終わらない。

まだまだ掛かりそうなので、その前に Mono 3.2.7 と F# 3.1 の組みあわせが Linux 上で動くかどうか確認しておこう。RasPi の CPU は、ARM1176JZF-S なので ARM になる。F# のアセンブリがそのまま動けばいいのだが…これはどうなんだろう?中身は機種依存していない感じなんだが。

■CentOS に g++ を入れる

sudo yum install gcc-g++

最新の CentOS には apt-get が使えなくなっているそうなので yum を使う。手元の Raspberry Pi は http://www.raspberrypi.org/downloads/ から RASPBIAN Debian Wheezy を使っているのでそれに揃えればいいのだが…いや、一旦そろえてみよう。

CentOS 上では Mono 3.2.7 はビルドできるのだが(多々エラーがでているのが気になるけど)、その後、F# 側で ./autogen.sh –prefix /usr すると、

[masuda@centos fsharp]$ ./autogen.sh --prefix /usr
checking whether make sets $(MAKE)... yes
checking for pkg-config... /usr/bin/pkg-config
configure: "pkg-config: /usr/bin/pkg-config"
configure: "PKG_CONFIG_LIBDIR: "
configure: error: "You need mono 3.0"
[masuda@centos fsharp]$

になって詰む。ピンポイントで mono 3.0.x が必要なのだろうか?

■Debian で Mono/F# をビルドする。

Debian のレポジトリには F# パッケージがあるのだが、http://fsharp.org/use/linux/ に従って Mono からビルドしていく。コマンド自体も apt-get が使えるのでそのままコピペしながら実行。途中でたらたらと Mono をビルドしている Raspberry Pi を追い抜いて、F# のビルドまで実行している途中。あっさり、Mono 3.2.7 の問題もスルーしていったので、おそらく Raspberry Pi のレポジトリにある Mono が古いバージョンなのかもしれない。

■Respberry Pi で mono のビルドが続く

約15時間ほどかけて Raspberry Pi 上で Mono のビルドが完了。USB メモリ上でやっているので、アクセスが遅くてビルドが遅いという話もある。8GB の SD メモリを使うと幾分はやいかも。

続けて F# のビルドに入るのだが、早々に Mono 3.2.7 の問題をクリアした。やっぱり Raspberry Pi レポジトリの Mono パッケージがおかしいらしい。OS のバージョンとかもあるのかもしれないが、それぞれの最新版で作ると通るので、ひとまず安心。

カテゴリー: F#, RaspberryPi | Mono と F# を CentOS/Debian 上でビルドしている途中 はコメントを受け付けていません

Raspberry Pi で F# を動かすまで…なんだがまだ終わらず

随分前から Raspberry Pi を持っているのですが、しばらく放置中だったので再開。LEGO Mindstorms EV3 を動くところまで続ける予定です。

最初は mono と F# を入れるところまで

■ Mono をインストールする

Mono on RaspberryPi でHelloWorld – 銀の光と碧い空 を参考にして

sudo apt-get install mono-complete

で一発インストールです。私の場合 SD カードが 2GB という小さいメモリだったので、mono を入れた途端に df が 100% になって詰み。仕方がないので、余っていた 4GB の SD カードに OS を入れ直して再インストールする羽目に。

# 追記
# respi-config で Expand Filesystem すると、SD カード一杯に容量を拡張します。初期状態では、ディスクイメージのために 2.6GB ぐらいしかないんですね。実行すると手元の 8GB のメモリを認識できました。

…が、いざ Use F# on Linux | The F# Software Foundation を参考にして、

sudo apt-get install fsharp

しようとしたものの git clone した後に make したところで再びメモリ不足。F# のビルドは結構容量が多いのですね(と思ったけど、間違えて mono をビルドしてた orz、まあ USB メモリのマウントの方法が分かったので良しとするか)

さて、8GB の SD カードがあればいいのですが、手元にないので思案。幸いにして手元に USB メモリならばあるので、USBメモリのマウント : ふじかわ家のページ を参照してマウント。

mount /dev/sda1 /mnt/usbmem

が、更に問題があって、この USB メモリは FA32 フォーマットのために Linux で使う chmod 777 とかが正しく動かない。パーミッションを正しく動作させるためには ext3 あたりでフォーマットしなおさないと駄目なので、CentOS : USBメモリをLinux用にフォーマット « Demence/Cup fdisk でパーティションを削除したのち、mkfs.ext3 でフォーマット

fdisk /dev/sda1
...
mkfs.ext3 /dev/sda1

■F#をビルド…がエラーになるので

やっとこさ準備が整ったので git clone してからビルド…なのだが、make でエラーになる。

FSharp Build error on the Raspberry Pi under Mono 3.2.7 · Issue #260 · fsharp/fsharp
https://github.com/fsharp/fsharp/issues/260

と同じ現象で、手元のバージョンは Mono 3.2.8 で直っているはずなのだが。raspberry pi の mono-complete が何らかのタイミングで古いのかもしれない。仕方がないので、元に戻って mono からビルドをする。

という訳で、mono からビルド中。6時間経ったがまだ終わらず。

image

カテゴリー: F#, RaspberryPi | Raspberry Pi で F# を動かすまで…なんだがまだ終わらず はコメントを受け付けていません

Xamarin.Forms でネイティブのイベントハンドラを拾う(iOS/Android編)

Xamarin.Forms でネイティブのイベントハンドラを拾う(Windows Phone編) | Moonmile Solutions Blog
http://www.moonmile.net/blog/archives/5908

の続きです。やり方は同じなのですが、iOS/Androidの場合にはネイティブのコントロールには Name プロパティがないので、Windows Phone のような FindName メソッドはないですね。iOS の場合は Outlet、Android の場合は FindViewById になるので、操作がちょっと違います。このあたりは、似たような操作(あるいは、適当なメソッドで包んでしまう)にしないと、手間がかかるので後でまとめていきましょう。

■iOSのRendererを表示する。

iOS の場合は、画面のルートが UIViewController で、その下の各種の UIView があります。Xamarin製XAMLでPageオブジェクトを作成した後は、CreateViewControllerメソッドでUIViewControllerを作ります。

public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
    Forms.Init();

    window = new UIWindow(UIScreen.MainScreen.Bounds);
    // window.RootViewController = App.GetMainPage().CreateViewController();
    var page = App.GetMainPage();
    window.RootViewController = page.CreateViewController();
    window.MakeKeyAndVisible();
    Disp(window.RootViewController);

    return true;
}

void Disp(UIViewController vc, string spc = "")
{
    Debug.WriteLine("{0}{1}", spc, vc.GetType().Name);
    Disp(vc.View);
}
void Disp(UIView vi, string spc = "")
{
    Debug.WriteLine("{0}{1}", spc, vi.GetType().Name);
    foreach (var it in vi.Subviews)
    {
        Disp(it, spc + " ");
    }
}

■iOSのネイティブコントロールにイベントをつける

方法は Windows Phone と同じで、レンダラのツリーを探索してネイティブのコントロールを探し出します。Xamarin製XAMLには名前をつけておいて、対応するネイティブコントロールを返す SetNamePageToUIelement メソッドを作ります。

UIControl SetNamePageToUIelement(string name, Xamarin.Forms.Page page)
{
    var el = page.FindByName<View>(name);
    if (el != null)
    {
        var rend = FindRenderer(el);
        if (rend != null)
        {
            // var en = rend as EntryRenderer;
            // en.Control.Name = name;
            // リフレクションで
            var pa = rend as UIView;
            var pi = pa.GetType().GetProperty("Control");
            var obj = pi.GetValue(pa);
            //obj.GetType().GetProperty("Name").SetValue(obj, name);

            return obj as UIControl;
        }
    }
    return null;
}

UIView FindRenderer(View ent)
{
    return Search(window.RootViewController.View, ent);
}
UIView Search(UIView el, View ent)
{

    var pa = el as UIView;
    if (pa != null)
    {
        var pi = pa.GetType().GetProperty("Element");
        if (pi != null)
        {
            var enel = pi.GetValue(pa);
            if (enel == ent)
            {
                return pa;
            }
        }
        foreach (var it in pa.Subviews)
        {
            var ret = Search(it, ent);
            if (ret != null)
            {
                return ret;
            }
        }
    }
    return null;
}

レンダラのツリーでペアになっている、Xamarin製コントロールとiOS謹製コントロールは、それぞれ Element プロパティと Control プロパティで取得できます。ただし、レンダラーで使ってるクラスが ViewRenderer<TView, TNativeView> のようにジェネリックになっているため、各コントロールごとにクラスが作成されています。対応するコントロールに対してのキャストをいちいちやってもいいのですが、所詮プロパティだけが欲しいのですから、リフレクションを使って省力化します。

ネイティブコントロールは UIControl を基底クラスにしているので、これを戻します。各種のイベントを付加したい場合は、もとのクラスにキャストする必要あります。

public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
    Forms.Init();

    window = new UIWindow(UIScreen.MainScreen.Bounds);
    // window.RootViewController = App.GetMainPage().CreateViewController();
    var page = App.GetMainPage();
    window.RootViewController = page.CreateViewController();
    window.MakeKeyAndVisible();
    Disp(window.RootViewController);

    UIControl uc = SetNamePageToUIelement("textUserName", page);
    var obj = uc as UITextField;
    obj.AllTouchEvents += obj_AllTouchEvents;

    return true;
}

■AndroidでRendererを表示する

Androidの場合は明示的なコンバーターを呼び出していません。SetPage メソッド内で隠蔽化されていて、レンダラのルートが解りづらいのですが、this.Window.DecorView でルートとなるビューが取得できます。ややこしいのですが、Android.Views.View と Xamarin.Forms.View と名前が混在しています。Xamarin.Forms.View のほうは、Xamarin製XAMLで使うViewで、Android.Views.View のほうはレンダリングツリーの構築のための View です。

protected override void OnCreate(Bundle bundle)
{
    base.OnCreate(bundle);

    Xamarin.Forms.Forms.Init(this, bundle);

    // SetPage(App.GetMainPage());
    var page = App.GetMainPage();
    SetPage(page);
    Disp(this.Window.DecorView);
}

void Disp(Android.Views.View vi, string spc = "")
{
    System.Diagnostics.Debug.WriteLine("{0}{1}", spc, vi.GetType().Name);
    var vg = vi as ViewGroup;
    if (vg != null)
    {
        for (int i = 0; i < vg.ChildCount; i++)
        {
            var v = vg.GetChildAt(i);
            Disp(v, spc + " ");
        }
    }
}

Android の場合、子コントロールを取得するためには ViewGroup にキャストをします。Children コレクションを持たせてもいいような気がするのですが、Android はそういう流儀みたいです。

■Androidのネイティブコントロールにイベントを設定する

戻り値のオブジェクトが Android.Views.View になるだけで、iOS と動作は同じです。このあたりは、Windows Phone も含めてライブラリ化したいところですね。

Android.Views.View SetNamePageToUIelement(string name, Xamarin.Forms.Page page)
{
    var el = page.FindByName<Xamarin.Forms.View>(name);
    if (el != null)
    {
        var rend = FindRenderer(el);
        if (rend != null)
        {
            // リフレクションで
            var pa = rend as Android.Views.View;
            var pi = pa.GetType().GetProperty("Control");
            var obj = pi.GetValue(pa);

            return obj as Android.Views.View;
        }
    }
    return null;
}

Android.Views.View FindRenderer(Xamarin.Forms.View ent)
{
    return Search(this.Window.DecorView, ent);
}
Android.Views.View Search(Android.Views.View el, Xamarin.Forms.View ent)
{

    var pa = el as Android.Views.View;
    if (pa != null)
    {

        var pi = pa.GetType().GetProperty("Element");
        if (pi != null)
        {
            var enel = pi.GetValue(pa);
            if (enel == ent)
            {
                return pa;
            }
        }
        var vg = pa as ViewGroup;
        if (vg != null)
        {
            for (int i = 0; i < vg.ChildCount; i++)
            {
                var ret = Search(vg.GetChildAt(i), ent);
                if (ret != null)
                {
                    return ret;
                }
            }
        }
    }
    return null;
}

イベントの種類が、iOS/Android/WP と随分違うので一概に共通化できませんが、それぞれのネイティブのイベントを使うことができます。

protected override void OnCreate(Bundle bundle)
{
    base.OnCreate(bundle);
    Xamarin.Forms.Forms.Init(this, bundle);

    // SetPage(App.GetMainPage());
    var page = App.GetMainPage();
    SetPage(page);
    Disp(this.Window.DecorView);

    Android.Views.View vi = SetNamePageToUIelement("textUserName", page);
    vi.FocusChange += vi_FocusChange;
}

おそらく、将来的には基本的なタップイベントのようなものは、Xamarin.Forms で実装されるでしょうから、こまめに共通化してもあまり意味はないかなと思っています(まあ、現時点では Click イベントぐらいしかないので、実務的な意味あるんですが)。むしろ、スワイプやピンチのような特有な操作を共通にしておくとライブラリ的に意味があるかもしれません。ちょっとそのあたりは Xamarin.Forms のイベント絡みがどうなるのかが不明なので、なんとも言えませんね。

ただ、自前の TMPuzzle を移植してみた感じでは、圧倒的にイベント絡みの処理は足りなそうなので、なんらかの補完はしないと駄目そうです。ゲームアプリの場合には、ピンチ、スワイプ、コマのスライド、得点のアニメーションなど、通常のコントロールにはない操作が出てくるので、そのあたりが必要です。ええ、もちろん Unity や MonoGame を使えばいいんでしょうが、手軽に作れるパズルアプリってのは考えているので、そのあたりはおいおいと。

カテゴリー: 開発, Android, Xamarin, iOS | Xamarin.Forms でネイティブのイベントハンドラを拾う(iOS/Android編) はコメントを受け付けていません

Xamarin.Forms でネイティブのイベントハンドラを拾う(Windows Phone編)

Xamarin.Forms ではイベント絡みが隠蔽化されていて、ボタンのクリックイベントやテキストボックスの変更イベントぐらいしか発生しません。このため、パズルゲームでは画像(Imageタグ)のタップイベントを Xamarin.Froms でパズルゲームを作る(iOS/Android版) | Moonmile Solutions Blog のように TapGestureRecognizer を使っています。(今後はどうか分からないのですが)TapGestureRecognizer クラスでは、情報が何もわたってこなくてタップなりスワイプなりの操作をしようとすると、ネイティブな UI コントロールに切り替える必要が出てきます。なので、さっくっと作れそうなページであれば Xamarin.Forms で、複雑なコントロールの組み合わせであればネイティブで、ってことになるんでしょうが…いや、ちょっと待てよ。それぞれのプラットフォームでは、Content = TMPuzzleXForms.App.GetMainPage().ConvertPageToUIElement(this); のように、Xamarin.Forms の XAML から各プラットフォームへのコンバータが動いています。Windows Phone の場合は ConvertPageToUIElement、iOS の場合は CreateViewController が使われています。Android の場合は SetPage が直接呼び出されていて中身が不明ですが、たぶん内容は似た感じになっているハズです。

これは、Xamarin.Forms 製の XAML から、MS 製の XAML にコンバートしていることを示しているわけで、何等かの形で内部で Windows Phone 特有のコントロールにして持っています。少し調べていて、レンダリングの部分で Xamarin.Forms の Label から iOS の UILabel を取り出す – Qiita のように LabelRenderer などで変更できることが解りました。更に調べていくと、なんとか Renderer のようなものがいっぱいあります。

image

実は、直前のバージョンでは EntryRenderer が none public になっていて手が出せなかったのですが(iOS と Android の Renderer は public になっていました)。何故か、つい最近公開された、1.1.0.6201 では、ここの Renderer が公開になっていました。ええ、ついでに内部でペアでもっていてる Element プロパティと Control プロパティも public になっています(直前のバージョンでは、名前すら違っていたのは内緒です)。ここで、情報を整理すると、

  • Xamarin.Forms.ContentPage が Xamarin.Forms の XAML ツリーを持っている。
  • ConvertPageToUIElement 等を呼び出すと、MS 製の XAML ツリーを作成する。
  • 同時に、Renderer を含む UIElement のツリーを作成し、Xamarin 製と MS 製の対応をツリー状にして保持する。
  • Xamarin.Forms 製のコントロールは、Element プロパティで取得する。
  • MS 製のコントロールは、Control プロパティで取得する。

のような感じになっています。おおまかに書くとこんな感じです。中身をみるとテキストボックスの場合には、TextBox と Password の2つのコントロールを持っているので、Xamarin.Forms 側では Entry 、MS XAML では Canvs になっています。

image

なので、Xamarin.Forms 側のコントロールから、うまく MS XAML のコントロールを見つけてやれば、Tap や Mouse イベント等のネイティブなイベントを設定できるはずです。

■Renderer のツリー を覗いてみる

ためしに、Windows Phone の MainPage クラスのコンストラクタを弄って、ツリーを書き出してみます。

public MainPage()
{
    InitializeComponent();

    Forms.Init();
    Content = TMPuzzleXForms.App.GetMainPage().ConvertPageToUIElement(this);
    Disp(Content);
}

 

void Disp(UIElement el, string spc = "")
{
    var pa = el as Panel;
    if (pa == null)
    {
        Debug.WriteLine("{0}{1}", spc, el.GetType().Name);
    }
    else
    {
        Debug.WriteLine("{0}{1} '{2}'", spc, pa.GetType().Name, pa.Name);
        foreach (var it in pa.Children)
        {
            Disp(it, spc + " ");
        }
    }
}

これを実行すると、こんな感じに Renderer のツリーが取得できます。Name プロパティを出力してみたのですが、残念ながら空になっています。名前は別途 FindName で検索しないと駄目っぽいです。

Canvas ''
 PageRenderer ''
  ViewRenderer ''
   LabelRenderer ''
    TextBlock
   ViewRenderer ''
    EntryRenderer ''
     Canvas ''
      PhoneTextBox
      PasswordBox
    LabelRenderer ''
     TextBlock
    LabelRenderer ''
     TextBlock
    LabelRenderer ''
     TextBlock
    LabelRenderer ''
     TextBlock
    LabelRenderer ''
     TextBlock
    LabelRenderer ''
     TextBlock
   ViewRenderer ''
    ImageRenderer ''
     Image
    ImageRenderer ''
     Image
    ImageRenderer ''
     Image

■ Entry コントロールを見つけ出して、イベントを設定する

しかし、Element プロパティを調べれば、対応する Control プロパティで Windows Phone のコントロールが見つかることが分かったので、試しに Entry コントロールだけチェックしてみます。

public MainPage()
{
    InitializeComponent();

    Forms.Init();
    this.page = TMPuzzleXForms.App.GetMainPage() as TMPuzzleXForms.MainPage;
    // Content = TMPuzzleXForms.App.GetMainPage().ConvertPageToUIElement(this);
    this.Content = page.ConvertPageToUIElement(this);
    Disp(Content);

    SetNamePageToUIelement("textUserName", this.page);
    var obj = this.FindName("textUserName") as UIElement;
    obj.LostFocus += obj_LostFocus;
}

void obj_LostFocus(object sender, RoutedEventArgs e)
{
    Debug.WriteLine("lost focus");
}

Xamarin.Forms 側で textUserName と名前つけたコントロールに対応する Windows Phone のコントロールを見つけ出します。そして、LostFocus 時にデバッグ出力するコードです。

ツリーから探し出すコードはこんな風になります。コントロールを直接返すのではなく、いちど Xamarin.Forms で付けた名前と同じものを Windows Phone のコントロールにもつけています。こうすると、後から FindName で見つけられるので汎用性があります。

void SetNamePageToUIelement(string name, Xamarin.Forms.Page page )
{
    var el = page.FindByName<Entry>(name);
    if (el != null)
    {
        var rend = FindRenderer( el );
        if (rend != null)
        {
            var en = rend as EntryRenderer;
            en.Control.Name = name;
        }
    }
}

UIElement FindRenderer(Entry ent)
{
    return Search( this.Content, ent );
}
UIElement Search(UIElement el, Entry ent)
{
    var pa = el as Panel;
    if (pa != null)
    {
        var en = pa as EntryRenderer;
        if (en != null && en.Element == ent)
        {
            return en;
        }
        foreach (var it in pa.Children)
        {
            var ret = Search(it, ent);
            if (ret != null)
            {
                return ret;
            }
        }
    }
    return null;
}

まあ、いちいち探索をすると遅くなってしまうので、一度 Xamarin.Forms のツリーを Renderer で探索してしまってから名前を付けるとよいでしょう。このあたりは、後日やる予定。

ネイティブのコントロールイベントが取れるので Image コントロールの Tap イベントも付加できます。おそらく、iOS/Android も同じ方式でできると思うので、このあたりは共通して使えるようにしていきます。ちょっとやっかいなのは、EntryRenderer クラスは共通のインターフェースから継承されていなくて、ViewRenderer<Entry, System.Windows.Controls.Canvas> な感じでひとつひとつジェネリックが使われてるってところですね。取得したいところが、Control プロパティと Element プロパティなので、共通に持っている Canvas では駄目という…ここは各コントロールごとに書くしかないのかな。あるいはリフレクションを使うとうまく作れるかも。

    public class VisualElementRenderer<TElement, TNativeElement> : Canvas, IVisualElementRenderer, IRegisterable
        where TElement : Xamarin.Forms.VisualElement
        where TNativeElement : System.Windows.FrameworkElement
    {
        public VisualElementRenderer();

        protected bool AutoPackage { get; set; }
        protected bool AutoTrack { get; set; }
        public UIElement ContainerElement { get; }
        public TNativeElement Control { get; }
        public TElement Element { get; }
        protected VisualElementTracker Tracker { get; set; }

このテクニックを、月曜日のコンテストに間に合わせるか…どうかは不明。どうせならば汎用的に作っておきたいし、Image コントロールのタップは3機種同じように作りたいので。

カテゴリー: Windows Phone, Xamarin | Xamarin.Forms でネイティブのイベントハンドラを拾う(Windows Phone編) はコメントを受け付けていません

Xamarin.Froms でパズルゲームを作る(Windows Phone版)

昨日の続きで…と言いますか、実装は昨日のうちに済ませました。移植自体は簡単で1時間かかりません。

image

ちょっと、XAMLを書き直して、コマの大きさを変えたりセンタリングしたりしています。

■ファイルアクセスは ApplicationData.Current.LocalFolder を使う

基本的なところは、iOS/Android と同じなのですが、ファイルアクセス部分がちょっとだけ違います。iOS/Android の場合は、System.Environment.GetFolderPath を使って普通のフォルダアクセス(といえ、アプリ内のフォルダだけなのですが…システムフォルダへのアクセスは要調査)と同様に使えますが、Windows Phone の場合は、ApplicationData.Current.LocalFolder を使います。これは WinRT と同じで、アプリからアクセスできるフォルダが OS 上で制限されているためですね。

このサンプルが「共有プロジェクト」を使っているのは、このためでもあって、以下のように #if でコンパイル時に分岐させます。PCL でやると、ここのコードビハイドが委譲を使ったりして面倒なので、そのままコード共有で。

var se = new XmlSerializer(typeof(MyData));
try
{
#if __IOS__ || __ANDROID__ 
    var documents =
        System.Environment.GetFolderPath(System.Environment.SpecialFolder.MyDocuments);
    var file = System.IO.Path.Combine(documents, "mydata.xml");
    using (var stream = System.IO.File.OpenRead(file))
    {
        var m = se.Deserialize(stream) as MyData;
        m.CopyTo(_model);
    }
#else
    using (var stream = await Windows.Storage.ApplicationData.Current.LocalFolder.OpenStreamForReadAsync(
        "mydata.xml"))
    {
        var m = se.Deserialize(stream) as MyData;
        m.CopyTo(_model);
    }
#endif
}
catch
{
    // 各スコアを0にする
    this._logic.Reset();
}

stream を取るところは一緒なので、Windows Phone で使っている OpenStreamForReadAsync メソッドを、適当に包んでやれば共有化できるのですが…まあ、このままで。気になるのは、iOS/Android で使っているのは OpenWrite で同期メソッドなんだけど、Windows Phone の OpenStreamForReadAsync は非同期メソッドってところですよね。ここは非同期に揃えたいところです。

■ゲームロジックやAzure Mobile Serivces は、PCL で

image

PCL(移植可能)を使っているのはゲームロジックとAzure Mobile Service のところです。カメラ機能とかは Xamarin.Mobile を使えば共有化できるので、シンプルなものならば結構すんなり共有化できるかなと。ただし、カメラを撮った後の遷移が各プラットフォームで若干異なるので、そのあたりはひと工夫が必要そうです。

■画像リソースはどうする?

このアプリでは、画像ファイルを

_mk[0] = ImageSource.FromFile("MarkNone.png")

な感じでファイル名を指定して直接取ってきています。ここのルートが何処を指すかというと、プラットフォーム毎に違っていて、

iOS /Resources/MarkNone.png
Android /Resources/Drawable/MarkNone.png
WinPhone /MarkNone.png

ってな感じで、Windows Phone はプロジェクト直下を示しているという…画像ファイルがちりばめられるのは嫌なので、このあたり WinPhone のために Images フォルダを作成して、

iOS /Resources/Images/MarkNone.png
Android /Resources/Drawable/Images/MarkNone.png
WinPhone /Images/MarkNone.png

とかにしたいところですね。ちなみに、Windows Phone には Resources というフォルダがあるのですが、そこは参照していません。

ただし、画像がたくさんあったり多言語化を考えると、リソースを使いたいわけで、そのあたりは Xamarin.iOS/Android で、文字列と画像をPCLを使って共有させる方法 を使って PCL にしたいところです。ここでの方法は iOS/Android しか対応していないので、WinPhone と WinRT にも拡張したいところですね。

■サンプルコード

もう少し手を入れますが、現状のは Github に
https://github.com/moonmile/TMPuzzleXForms

カテゴリー: Android, Xamarin, iOS | Xamarin.Froms でパズルゲームを作る(Windows Phone版) はコメントを受け付けていません

Xamarin.Froms でパズルゲームを作る(iOS/Android版)

de:code の直前に発表になった Xamarin.Forms ですが、拙著のサンプルも、それぞれビューを作っているわけで。

日経BP書店|C#によるiOS、Android、Windowsアプリケーション開発入門
http://ec.nikkeibp.co.jp/item/books/P98340.html

そんな訳で、サンプルコードの TMPuzzle を Xamarin,Forms にコンバートしています。サンプル自体は一枚絵(ひとつのビュー)になっているので、比較的コンバートは楽なハズ…なのですが、いくつかコツが要りそうなでメモ的に残しておきます。

まだ途中の段階ですが、iOS/Android版を Github に公開しておきます。
https://github.com/moonmile/TMPuzzleXForms

■ビューを XAML で作る

https://github.com/moonmile/TMPuzzleXForms/blob/master/TMPuzzleXForms/TMPuzzleXForms/MainPage.xaml

サンプルでは、axml/storyboard/XAML で作ったので、今回も XAML で作ります。Xamarin Studio ではデザイナは動かないのですがコード補完ができるのでだいたいの動きが想像できます。デモのサンプル https://github.com/xamarin/xamarin-forms-samples にある ButtonXaml が XAML を使ったコードです。*.xaml と *.xaml.cs の2つがあるので、コードビハイドが書けます。MVVM スタイルにするときはバインドを使えばいいのですが、ここではがりがりとコードを書きつけてしまいます。バインド自体は、MS謹製のXAMLと同じように Text=”{Binding …}” の構文で書けるので、ここは便利。使えるコントロールは http://iosapi.xamarin.com/?link=N%3aXamarin.Forms を参照すれば OK です。TextBox が Editor になっているとか、いくつか違いがありますが、このあたりは iOS/Android/Windows の混合になるので仕方がないところです。

ビュー自体は、レイアウトが異なるので、http://developer.xamarin.com/guides/cross-platform/xamarin-forms/controls/layouts/ を見てベースを決めます。TMPuzzle は Windows ストア寄りに作ってあるので Grid を使ってみたのですが、iOS だとうまくレイアウトができませんね。スマートフォンのような小さ目の画面であれば? Frame を使って iOS のように位置固定(Windows の Xaml ならば canvas)で良いかもしれません。TMPuzzle 自体はゲームアプリなので、たくさんのコントロールを乗せていますが、普通のコンテンツを表示するならば、ContentViewStackLayout でもいいかもしれません。

image

プロジェクトの構成は、Blank App (Xamarin.Forms. Shared) を使っています。PCL でも良いのですが、サンプル自体はコードビハイドを使っているのと、プラットフォームごとの処理が必要になって時には共有プロジェクト内で #if してしまえばよいので、こっちのほうが融通が利きます。

image

https://github.com/moonmile/TMPuzzleXForms/blob/master/TMPuzzleXForms/TMPuzzleXForms/App.cs 共有プロジェクトの App.cs を書き換えます。MainPage.xaml を共有プロジェクトに追加したので、new MainPage() でページを作成します。コードビハイドの場合は、このあとゴリゴリ内容を書いていますが、ひとまず XAML を書いて Andorid か iOS のシミュレーターで動かすとよいでしょう。

public class App
{
	public static Page GetMainPage()
	{
		return new MainPage();
	}
}

画像リソースも多分、共有プロジェクトにおけるハズなのですが、フォルダが異なる(Android の場合は Resources/Drawable、iOS の場合は Resources)となるので、各プラットフォームのフォルダに置いています。画像リソースは一律、

var img = ImageSource.FromFile("MarkNone.png");

のように取り出せるので、iOS/Android を区別する必要はありません。

ちなみに、Xamarin.Forms とは関係ないですが、ファイル呼び出しは

var file = System.IO.Path.Combine(documents, "mydata.xml");

のように共通化できます(Windows Phone の場合は調査中)。

■MainPage.xaml.cs

https://github.com/moonmile/TMPuzzleXForms/blob/master/TMPuzzleXForms/TMPuzzleXForms/MainPage.xaml.cs

ページを表示するときの初期化は、Android では OnCreate、iOS では ViewDidLoad になるのですが、Xamarin.Forms では(多分)OnAppearing です。 ヘルプを見ると When overridden, allows application developers to customize behavior immediately prior to the Xamarin.Forms.Page becoming visible. とあるので、次回表示するときも呼び出されてしまうような気がするのですが、ここは要調査ですね。TMPuzzle は1枚絵なのでこれを使っています。

各プラットフォームで呼び出す MainActiveity や AppDelegate はそのままです。もともと共通化を意識して作ったサンプルプログラムなので、Xamarin.Forms に移植するとプラットフォーム毎の差がほとんどなくなって、画像ファイルの切り替えぐらいになります。

■画像のクリックイベントはTapGestureRecognizerを使う

Button コントロールには Click イベントがあるのですが、ImageやLabelなどには Click イベントがありません…というか、タップイベント全般がありません。ざっと調べてみると、コントロールに対するユーザーイベントは Click と TextChanged ぐらいしかありません。
うーむ、困った。これで万事休すかな、と思ったのですが TapGestureRecognizer ってのがありました。iOS と同じでコントロールに対するイベントを取ってきます。

TapGestureRecognizer tapGestureRecognizer = new TapGestureRecognizer
{
    TappedCallback = img_Click
};
// 表示用マークにイベントをつける
_marks = new Image[DataModel.BOARD_X_MAX * DataModel.BOARD_Y_MAX];
_tags = new Dictionary<Element, int>();
for (int i = 0; i < DataModel.BOARD_X_MAX * DataModel.BOARD_Y_MAX; i++)
{
    var img = _marks[i] = this.FindByName<Image>(string.Format("mark{0}", i));
    img.GestureRecognizers.Add(tapGestureRecognizer);
    _tags[img] = i;
}

こんな風に、イベント先の img_Click を設定しておいて、img.GestureRecognizers.Add のように追加していきます。GestureRecognizers 自体は、View クラスにあるので大抵のコントロールにはついています。

いわゆる sender が View オブジェクトで渡されるので、これを目的のコントロールにキャストします。引数自体は object 型なのですが、中身は不明。Image をクリックすると null が来ています…が、ひとまず画像やラベルのタップイベントを取得できます。

public async void img_Click(View view, object args)
{
    // 再入禁止
    if (_flag == true) return;
    _flag = true;
    Image mark = view as Image;

■Android と iPhone の動作

同じ XAML ファイルを使ったのですが、iOS のほうがレイアウトが崩れています。というか、Grid だとちょっと辛いものがありそうですね。Xamarin.Forms のサンプルは、flowlayout を使っているので、どれも同じようになりますが、複雑なレイアウトの場合にはそれぞれの調節が必要っぽいです。

image

image

引き続き Windows Phone を作成。

カテゴリー: Android, Xamarin, iOS | Xamarin.Froms でパズルゲームを作る(iOS/Android版) はコメントを受け付けていません

Dynabook Tab VT484 で Kindle を動かす

Windows タブレット dynabook Tab VT484 トップページ
http://dynabook.com/pc/catalog/d_tab/131118vt484/index_j.htm

de:code の「教材」として配布されたタブレットですが、何に使うのか…とおもったけど、ひとまず Kindle を入れます。以前やった Windows 8 Pro に Bluestacks を入れれう方法と同じです。

日本語Windows 8 Pro で Kindle を動かす方法 | Moonmile Solutions Blog
http://www.moonmile.net/blog/archives/4606

タブレットなので

  • Kindle と同じように使える?
  • Suface RT だとエミュレータが入らないけど、Dynabook Tab の場合は Windows 8.1 だから大丈夫。

ってことです。エミュレーター上で動くので若干動きが遅い(特にストレージアクセス時が遅い?)のですが、一度立ち上げてしまえば普通に読める状態になります。WiFi 経由が遅いのか、エミュレーターが遅いのか分からないのですが、漫画を読み込んだときにかなり待たされますが、これも一度読み込めば普通にページがめくれます。

こんな感じに横置きにすると2ページレイアウトで。

image

縦置きにすると1枚のレイアウトになります。

20140608_02

Bluestacks のほうは、bluestacks.com から、ダウンロードすれば OK。

■解像度を変更する

普通に Bluestacks を Danyabook tab に入れただけだと、こんな風にタブレットを縦にしても、画面が横になります。逆にタブレットを横にすると bluestacks の画面が横になります。

image

おそらく、タブレットの向きと bluestacks の向きの認識が逆転してるんですよね。幸いにして、Bluestacks は解像度を変えられるので、縦横を逆転させて設定します。

我的PC古箱 dynabook Tab VT484 購入レビュー / カスタマイズ/ VT484/26K PS48426KNLG
http://sc440ge.blog59.fc2.com/blog-entry-177.html

解像度はレジストリにあります。

[HKEY_LOCAL_MACHINESOFTWAREBlueStacksGuestsAndroidFrameBuffer]
“Width”=dword:0000042a
“Height”=dword:00000258
“Depth”=dword:00000010
“FullScreen”=dword:00000000
“WindowState”=dword:00000001
“HideBootProgress”=dword:00000001
“EmulatePortraitMode”=dword:00000001

元の解像度が 1066 x 600 の変則パターンなので、

[HKEY_LOCAL_MACHINESOFTWAREBlueStacksGuestsAndroidFrameBuffer]
“Width”=dword:000002F8
“Height”=dword:000004D8
“Depth”=dword:00000010
“FullScreen”=dword:00000000
“WindowState”=dword:00000001
“HideBootProgress”=dword:00000001
“EmulatePortraitMode”=dword:00000001

これを 760 x 1240 にします。これは、dynabook tab の 800 x 1280 から 40 ずつ引いた値です。800 x 1280 に設定すると何故か縦置きのときに Kindle がうまく表示できないんですよね。そこで縦横からタスクバーの幅(40ドット)だけ引いています。

これを bluestacks-760×1240.reg のようにファイルに保存して、ダブルクリックすればレジストリに書き込まれます。

ちなみに、dynabook tab はミニ usb なので、普通の USB キーボードがつなげられません(コンバーターを使うか、bluetooth を使うか)。キーボード打ちはちょっと面倒なので、こんな風に「リモートアシスタンス」を使います。dynabook tab のほうで「msra」で動作させれば OK です。

image

本来ならば、手っ取り早く Windows 8.1 Pro にアップデートするのがいいのでしょうが、再インストールが必要なので躊躇しております。Update 版を1万ちょっとで買えばいいんだけど、それだけのために買うのもなぁ、という感じです。まあ、ファイル共有は普通の Windows と同じようにできるので、ファイルの受け渡しは楽ですね。Surface の場合は、別途レジストリを弄るか、ホームグループを使う必要がありますから。

普段使いは白黒 Kindle を使っているので、カラー版を見たいときに使うかなぁ、といったところ。あとは、ストアアプリ版だと面倒なので、WPF で自作ツールを入れるとか。主に動画ビューアとしてですが…いや違うか、「教材」なのだから、ぜひとも Lumia と一緒にユニバーサルアプリを作らないといけないわけですが。まだ Lumia は 8.1 にアップデートしておりませぬ。

カテゴリー: 雑談 | Dynabook Tab VT484 で Kindle を動かす はコメントを受け付けていません

F# の Async と C# の async/await を相互運用する方法…を模索中

de:codeも終わったので、勢いで Xamarin Tシャツアプリを F# に書き直してます。Xamarin Tシャツアプリってのは、http://xamarin.com/studio から Xamarin Studio をダウンロードして、ダウンロードしたソースコードをビルドすると Tシャツを注文するアプリが作れます。それを実際に送信すると、Xamarin 社が C# の Tシャツを送ってくれるという販促アプリです。
で、じゃあ、F# で書いたらどうなるのか?ってのと、F# で送ったら F# Tシャツを送ってくれるかどうか…は別として(多分無理でしょう)、F# のアプリが iOS/Android で動くよ、の実践版のつもりです。実際 C# のコードをダウンロードすると、Web Service に接続しているし、リストボックスとか POCO のデータアクセスなどを使っている、iOS のグラフィック機能を使ってごちゃごちゃやっているという結構な代物でした。その中で、サーバーアクセスなどで頻繁に await/async をやっています。

ざっと F# に書き直しながら思ったのは、

  • 非同期処理の async/await が頻繁に出てくる
  • データバインド絡みの Obeserver パターンが出てくる

この2点を F# でも書けないといけない。非同期処理自体は Windows ストアアプリでも頻繁に出て来るのですが、WinRT へ F# からアクセスできない(?)ので、まだ問題になっていない模様。しかし、Xamarin.iOS/Android を使って F# をアプリを作るときは、C# の async/await は避けられないわけで、このあたりはうまく C# と F# で相互運用したいところです。

Async in C# and F#: Asynchronous gotchas in C# (Japanese translation)
https://gist.github.com/pocketberserker/5565303
Async in C# and F#: Asynchronous gotchas in C#
http://tomasp.net/blog/csharp-async-gotchas.aspx/

これは、話題になった時にざっと読んで、F# と C# で Async の扱いが違うのか、漠然と思っていたわけですが、いやいやいや、Async が違うというんじゃなくて、そもそもこの話題で出てくる F# の Async はコンピュテーション式の AsyncBuilder で、C# の async/await は Awaitable パターンの実装だから、そもそもが違うがな(と自分が勘違い)していたことが、今日わかりました。なるほど。そうなると async/await を Async{} で単純に置き換えることができないわけで、更に言えば、.NET Framework の *Async メソッドの扱いと、F# の Async{} の扱いを両方やらないと駄目ってことですね。Task<‘T> と Async<‘A> ってことです。

■Async は Async<‘T> を返す

let workThenWait() =
  async {
      Thread.Sleep(1000)
      printfn "work done"
      do! Async.Sleep(1000)
  }

let demo() =
  let work = workThenWait() |> Async.StartAsTask
  printfn "started"
  work.Wait()
  printfn "completed"

workThenWait() が非同期で動いている間、待っているという書き方です。
Async.StartAsTask では、まだ実行されていなくて(タスクだけ作られて)、work.Wait() でタスクが実行されます。work の型は、Async<‘T> で、終了時に戻り値を返せます。

これを、素直に C# に直すと、こんな感じ。

async Task WorkThenWait()
{
    Thread.Sleep(1000);
    Console.WriteLine("work");
    await Task.Delay(1000);
}

async void Demo()
{
    Console.WriteLine("started");
    await WorkThenWait();
    Console.WriteLine("completed");
}

WorkThenWait() の位置が、started の後ろにずれて、await で非同期待ちをします。正確には非同期実行&待ちをするわけで、元ネタでいう、var child = WorkThenWait(); と child.Wait(); にあたります。
これから勝手に推測して、Async{} ってのを async/await に直せばよいか?って思うわけですが違っていて、C# の async/await のほうは Task<‘T> を返します。

■async/await は Task<‘T> を返す

下記の例では Task を返すように書き方もの。
C# では、async で修飾すれば、Task を返すのにラムダ式を使わなくてよいし、非同期待ちをするのに、Start(), Wait() を羅列しなくてもよい。更に戻り値を受けるときも、t.Result を使う必要もなく await が使える。

let workThenWait2() =
    new Task( fun _ ->
              Thread.Sleep(1000)
              printfn "work done"
              Thread.Sleep(1000)
            )

let demo2() =
    let t = workThenWait2()
    printfn "started"
    t.Start()
    t.Wait()
    printfn "completed"

int 型の戻り値を返したときは、こんな風に書く。

let workThenWait3() =
    new Task( fun _ ->
              Thread.Sleep(1000)
              printfn "work done"
              Thread.Sleep(1000)
              1 // 戻り値
            )

let demo3() =
    let t = workThenWait3()
    printfn "started"
    t.Start()
    t.Wait()
    let res = t.Result
    printfn "completed"

■何が問題か?

F# だけでやっているときは、Async{} を使えばいいのだけど、C# と相互運用したいときとか、非同期の .NET Framework クラスを使いたいとき(WebClientとか)に結構困る。Async と async/await が混在するのもそうだけど、Async<‘T> なのか、Task<‘T> なのかを区別しないといけない。

  • WebClient で使う Async 系のメソッドは、Task<‘T> を返すので、これに合わせる。
  • C# で作った Async 系のメソッドは、Task<‘T> を返す。
  • C# へ渡す非同期タスクは Task で渡す必要がある。
  • F# 内で閉じているときは Async{} を使う

というパターンが必要になる。

■F# 用の await を自作する

まず Task<‘T> を受けるための await を自作します。

type Async() =
    // await を自作する
    static member await (t:Task) =
        t.Start()
        t.Wait()
    static member await (t:Task<'a>) =
        t.Start()
        t.Wait()
        t.Result

一度、Await で包んであるのは、await メソッドを多重化するため。戻り値無しだけ作るという方法もありでしょう。
使い方は、C# の await とは違って、後ろにつけます。Async.StartAsTask と同じ方法ですね。

let demo2a() =
    printfn "started"
    workThenWait2() |> Async.await
    printfn "completed"

let demo3a() =
    printfn "started"
    let res = workThenWait3() |> Async.await
    printfn "completed"

同じように、Async<‘T> を引数に取る await メソッドも作っておきます。

type Async() =
    // await を自作する
    static member await (t:Task) =
        t.Start()
        t.Wait()
    static member await (t:Task<'a>) =
        t.Start()
        t.Wait()
        t.Result
    static member await (t:Async<'a>) =
        ( t |> Async.StartAsTask ).Wait()

こうすると、どちらの場合も Async.await で処理して統一できるので便利。

let demo1a() =
  printfn "started"
  workThenWait() |> Async.await
  printfn "completed"

■Task を作る TaskBuilder を作ればよい

C# の Task<‘T> は楽に処理できるようになったので、今度は F# で Task<‘T> を作って C# に渡す、というパターンを考える。async の task 版といったところ。

let workThenWait3() =
    new Task( fun _ ->
              Thread.Sleep(1000)
              printfn "work done"
              Thread.Sleep(1000)
              1 // 戻り値
            )

このようなラムダ式の書き方を、以下なようなコンピュテーション式に直せればOK。これは AsyncBuilder のソースを見て直せばいいかな?

let workThenWait3() = task {
              Thread.Sleep(1000)
              printfn "work done"
              Thread.Sleep(1000)
              1 // 戻り値
            }

こっちは後日。

~~~
こちらも参照

AsyncBuilder extension for maniplating other containers by using keyword | F# Snippets
http://www.fssnip.net/jj

カテゴリー: 開発, F# | 3件のコメント

de:code 2014 の感想戦

de:code | 日本マイクロソフトの開発者/アーキテクト向けイベント – Microsoft Events & Seminars
http://www.microsoft.com/ja-jp/events/developer/

結論から言えば、何かと前評判が悪かった de:code ですが、蓋を開けてみれば「損はさせません」のツイートは本当でした。値段相応なのか、値段以上なのかはさておき、自分の言ったセッションをメモ書きしておきます。

キーノートはプレゼントの発表が二転三転したのでさておき、

DE-023 Windows アプリ開発、どこへ向かうのか

お昼に「.NET開発テクノロジ入門 2014年版」を買って読みながら奥主さんの話を聞く。行く予定のプレゼン資料は事前に OneNote で配布されていたので、そのまま Surface に入れてひと通り見ておく。紙の資料がないので、手荷物が少なくてよい。メモしたいときは OneNote に書くか、自分のメモ帳に書くか。今回は Twitter にちらちらと流すだけで十分かと思ってメモは取らず。全体というか、de:code の歩き方になるので、デバイス関係の事前内容がわかる。

DE-018 Windows ストア アプリ開発、テスト、デバッグ、ストアへの提出

4人のエバンジェリストがリレー式にストアアプリの最初から最後までってことで、ひと通り流し。初心者向けになっているけど、この道は何度も通るし、少しずつ情報が変わる(便利になるという意味で)。WinJS は少し手を付けてみたい。

TL-003 最新 Web API 開発 ~ASP.NET API 2 とクラウドの活用~

ASP.NET MVC と Web API 絡みの情報集めとして。WCF の複雑さから、REST、OData にして疎通を簡単にする感じに向っている。クロスプラットフォーム(特にマルチクライアント)ならば当然の帰着という感じで。OData はなんとなくわかったので、後で認証まわりと合わせて、ASP.NET MVC と合わせて知識埋め。

DE-015 Visual Studio 2013 Update 2 と HTML5 によるクロスデバイス、クロスプラットフォーム開発の全貌

HTML5/WinJS を使って、ストアプリ、Windows Phone、ブラウザアプリを共通に作れるという話。ブラウザを含められるのは Javascript ならではで、これは、Xamrin.iOS/Android の WebView にも含められるかも。CORDOVA/PhoneGap を使えば、ブラウザ的な UI を持ってくるのは楽になる。逆にストアアプリ風の UI をブラウザに表示させることも可能。

DE-010 デスクトップ アプリケーションと Windows ストア アプリの連携

同じ PC にあるのに、デスクトップアプリとストアアプリの連携は非常に制限されている。のだが、Windows 8.1 Update からサイドローディングに限り、ローカル PC へのループバックを許可、さらにアプリブローカーを通してデスクトップの COM へアクセスできる。これができるということは、大抵の業務ロジックを COM にして動作させることが可能…なんだが、現実は View にべったりだったりして無理なんだろうな。デスクトップ DLL を有効に使いたいときに利用するテクニック。

SV-014 ハードウェア構築・管理のない世界 ~ Azure 仮想マシンの現実 ~

Azure プログラミングはいくつかやったけど、なぜか仮想マシンは作ったことがない。Linux を動かしたいならレンタルサーバを借りたほうが安いから、とも思っていたのだが、スナップショットを取れるとか、ローカルで作成した HD をアップロードできるから環境構築はこっちのほうが効率的かもしれん。試験用に CentOS+CakePHP で作ってみるかも。

DE-005 VWindows Phone 8.1 プラットフォーム徹底解説

Windows Phone は完全にノータッチだったのだが、ユニバーサルアプリがあるので、ストアアプリ(タブレットアプリ)からのアプローチのひとつとして聞きに行く。WP8 から Windows NT カーネルに変わったということで、WinRT と共有化できる準備ができる。Xamarin.iOS/Android に Xamarin.Forms が加わったので、UI 的にも Windows Store/Phone を加える環境が整ってきている。先の WinJS/HTML5/WebView と組み合わせる自由度が高い。ちなみに、私の教材は Lumia 1520 なので解像度がフルHD。電話にしてはでかいので、私としてはタブレットとして使う。Sim を持ってないし。

SN-005 C# を使い倒す iOS/Android 開発の新潮流

人のうわさを聞くためと、どんな人が興味があるのか?な感じでお昼。「C#によるiOS、Android、Windowsアプリケーション開発入門」に興味を持ってもらえるかってこと。環境としては、Visual Studio で作れるのだが、有償というのはそれなりに敷居が高い。カンファレンス内では使用期間3か月のチケットを配るそうなので、まずは使って貰えるパターンかと。ただし、Xamarin の本格的なターゲットは iOS/Android アプリ作成にあるので(今後は Windows Phone も加わるが)、通常のデスクトップアプリ作成経験だけだと難しいかも。Windows ストアアプリ作成との並行して行うのがおすすめ。あと、まだ Phone のほうに目が向いていることが多いが、実は Tablet のほうに勝機がある。

DE-017 Windows ストア アプリ で収益を上げるには

手元にもある「アプリ内課金+広告 iPhoneプログラミング」の Windows 版。いまのところ、アプリの有償手段は、「ユーザーに直接売る」「内部課金する」「広告を出す」の3種類しかない。無料の場合は「広告アプリとして出す」(最近の映画関連のゲームアプリとかがそれ)、「実力/テンプレートを示す」(他の案件とつなげる)というパターンがある。会社/個人の違いやターゲット(ゲーム/書籍/非ゲーム)もあるし、何を売るか?(コンテンツなのか技術なのか)ってのもある。Xamarinを含めると、iOS/Android/Windows Store/Windows Phone と 4種類になるので、これのそれぞれで、ダウンロード販売/アプリ内課金/広告を表示、の共通化を考える時期なのかも。

AR-006 マルチデバイスアプリ開発における設計戦略 ~ Webか? ネイティブか? あるいは両方か?

結論からあれば、いろいろ選択肢が用意されているので、前提条件(既存コンテンツか新規か、簡易アプリか複雑な操作か)によって選択する必要がある。既にブラウザコンテンツがあれば HTML5 をそのまま使えるパターンができるし、さらにちょっとして工夫が加えられる。WebView ならば Invoke を使うとか、逆にネイティブ操作でも詳細やヘルプ表示に WebView を使うとか。カードゲームアプリは WebView を使っているものが多いが、逆にマップはネイティブで作ってカード表示をネイティブらしくHTMLで作るという方法もある。

DE-006 ユニバーサル Windows アプリの画面設計 ~ 4 インチから 82 インチまで ~

実は iPod nano は正方形画面で、いくつかのフォト機器は正方形だったりする…のだが、そうそう、パズルアプリの画面を正方形にしておくと縦と横の両方に対応できる。で、旧スナップの横 500px の縦置きが今後の考えどころ。あと、flush paint のように、横置き全画面以外は動作しない、というのもアリなのかってのは目から鱗だった。確かにアプリがユーザーの使い方を規定してもよい。DPI に関しては考える必要がないし、DPI の高さについてはハード屋さんが熟知しているので、ソフト屋としてはもうちょっとアプリのほうに目を向けて。

DE-007 C#/.NET で iOS/Android アプリを開発 ~ Xamarin で実現するクロスプラットフォーム開発 ~

自分の締めとして Xamarin の話。デモは、おととい発表されたばかりの Xamarin.Forms を含めて。WebView で Razor を使うトリッキーなコードは、なるほどその手があったかという感じ。ループとかバインドを頻発するときには重宝しそうな感じ。いや、後からよく考えたら JQuery とか使ったほうがよいかも w。ただ、このカンファフェンスを通して Windows Phone, Xamarin で感じたのは、ここまで他のプラットフォームを連呼する Microsoft になったのだなということ。キーノートでもあったけど、Windows を連呼していた Windows DNA あたりの時期から一変している。

C#によるiOS、Android、Windowsアプリケーション開発入門 

日経BP書店|C#によるiOS、Android、Windowsアプリケーション開発入門
http://ec.nikkeibp.co.jp/item/books/P98340.html

そんなわけで、教材として貰った/買った dynabook tab と Lumia 1520 どうするかと模索中。現在dynabook のほうは windows 8.1 update までして、サブディスプレイ状態(苦笑)。Lumia のほうは 8.0 のままで…後で、開発者登録しないと。

カテゴリー: 開発 | de:code 2014 の感想戦 はコメントを受け付けていません

後付け言語 post を考えてみる

自前の関数型電卓のパースが間に合わなかったのと、先週の.NETラボ勉強会で「関数型言語の本質とは?」にうまく答えられなかったので、それっぽい言語を考えてみる。

うーん。私自身は関数型言語自体を扱っている期間が短いので、先駆者の言葉を借りれば「関数プログラミング」から「式が簡略化できる」ことと、「型システム入門」から「型が決まる/推論可能である」ことに尽きる…と思うのだけど、じゃあ、オブジェクト指向型言語との違いは?というと、なんだろう。
実は、「オブジェクト指向型言語は内部に状態を持つ、対して関数型言語は内部に状態を持たない」というのは正しいのだけど、オブジェクト指向型言語に根拠があるので、これは「ごまかし」である(ごまかしと分かっていて言うんだけど)。でも、状態を持たない(あるいは持てないように作る)ので、パラレル化がしやすいし、ドメイン駆動設計による分散に対象になる(内部にアトムを持たないので)。

で、懇親会で話したように、

  • 「オブジェクト指向による関数型言語」
  • 「関数型指向によるオブジェクト指向型言語」

ってのも考えられるわけで、どちらの排他的なものにはならない。特に F# の場合は、内部でクラスが作れるしオブジェクト指向的な .NET Framework も使えるわけで、そのあたりは良しなにハイブリット的に作れる。加えていれば、LISP は LISP なので、関数型言語に入れると怒る人がいるかもしれない。

以前、Ruby で後付メソッドが作れる、JavaScript のプロトタイププログラミングを知った頃に、すべてのメソッドのプロパティが virtual であればよかろうというのを思いついたことがある。今でいえば、C# の dynamic なんだけど、F# の型推論と組みあわせると、もっと静的言語に近い形で実現できないか?と妄想してみる。

view =
 name = "masuda tomoaki"
 address = "tokyo"
 age = 46

 button.click = 
  db.submit (name,address,age)

name is TextBox
address is ComboBox
age is TextBoxOnlyNumber
button is Button

.submit t = 
 insert into Person values ( t.name, t.address, t.age )

F# も C# もそうだけど、関数定義やクラス定義は前置参照が基本になる。これはコンパイル時点にワンパスになるような工夫でもあるし、コンパイル時の時間短縮でもある。しかし、Javascript や ruby のように後付けでメソッドが作れる場合は(先付のメソッドとは完全に同じではないにせよ)実行時にメソッドの存在をチェックすることになる。

が、これを型推論をフルに使って「あらゆるオブジェクトのメソッド/プロパティを後付けできる」と定義してしまう。先の例だと view で、やりたいことは「name, address, age の3項目があってデータベースに登録する」」ということなので、それを先に書く。これらがどういうものかは後で書く。

「name is TextBox」ってのは、正確に書くと「name that is TextBox」になる。詳細を that で補完していく英語の構文になる。先に適当なことを書いて、後から追記する方式です。

更に言うと、この .submit 部分はあとから上書きができて

.submit t = 
 insert into Person values ( t.name, t.address, t.age )

.submit t = 
 fs = open "person.txt"
 fs.write t.name t.address t.age

のように後ろに二番目の .submit をつけると、これが採用される。普通は前置メソッドが優先されるが、後付け言語 post では、後から定義したほうを採用するので、後ろの .submit が使える。

当然、null オブジェクトのメソッドはどうなるか?とか問題があるけど、Objective-C の nil のように、無視する。こうなると、obj.?method のような変な記号を使わなくていいので、タイピングが楽になる…ハズ。

もうちょっと適当に考えると、

main
 v1 = (10,20)
 v2 = (30,40)
 ans = v1 + v2
 printfn ans

main.(+) x y = 
 ( x[0] + y[0], x[1] + y[1] )

main.(+) x y = 
 ( x.0 + y.0, x.1 + y.1 )

main.(+) x y = 
 this.left  = x.left + y.left
 this.right = x.right + y.right

.left (x,y) = x
.right (x.y) = y

.left   (x,y,z) = x
.middle (x,y,z) = y
.right  (x,y,z) = z

こんな風にベクトルの計算を考える。型推論を使えば、2つの .right メソッドは容易に区別がつくので、間違わない。むろん、プログラミングしているときは間違えそうな気もするけど。

カテゴリー: 開発 | 後付け言語 post を考えてみる はコメントを受け付けていません