Xamarin.Forms 「ARC Welder」を使用してChromeブラウザで動作させて見た
ARC Welder
昨日(2015年4月3日)、GoogleからAndroidアプリをChromeで動作させるというニュースがありました。
ARCとは「Android Runtime for Chrome」の頭文字であり、Androidが使うAPIをラップして、ChromeブラウザまたはChrome OSで動かすランタイムとの事。まだ、ベータ版という事ですが・・・Xamarin.Formsで作成したAPKがうまく動作するかどうか試してました。
http://japanese.engadget.com/2015/04/02/google-android-chrome-arc-welder-apk/
Xamarin.Formsのプロジェクト
結論から言ってしまうと、アプリのアイコンを設定して、リリースビルドすれば、証明書のあるパッケージは、問題なく動作するようです。アイコン設定
プロジェクトテンプレートのデフォルトでは、アイコンが無いため、「ARC Welder」で「Launch App」時にエラーが発生してしまいます。ERROR: Required badging "icon" not found in package.
デバッグビルド
Xamarinのデバッグビルドは、高速化のため、「共有ランタイム(Shared Runtime)」などがリンクされていないのが原因だと思います。証明書
証明書が無いパッケージでは、「Launch App」まで行けますが、実行時にcrashします。作業手順
それでは、実際に行った手順を順に紹介してみたいと思います。
(1)プロジェクトは、「Blank App (Xamarin.Forms Portable)」テンプレートを使用します。
(2)構成マネージャで「Release」に変更します。
(3)Androidプロジェクトのプロパティで、アイコンを設定します。
(4)「ARC Welder」をインストールします。
https://chrome.google.com/webstore/detail/arc-welder/emfinbmielocnlhgmfkkmkngdoccbadn
(5)インストールが完了すると、「chrome://extensions」で利用可能になります。
(6)初回起動時に、作業ディレクトリの指定があるので、適当なフォルダを指定します。
(7)「Add your APK」で、Releaseビルドの証明書がある方を選択します。(App1/App1.Droid/bin/Release/App1.Droid-Signed.apk)
(8)Orientationで「Portrait」、Form Factorで「Phone」を選択して「Launch App」を押します。
(9)起動が確認できます。
(10)「Launch App」で成功したアプリは、「拡張機能」の一覧に入り、次からは、ここから起動できます。
Xamarin.Forms.Maps
試しに、Xamarin.Forms.Mapsを起動してみましたが、「Play開発者サービスの入手」をクリックするとクラッシュしましたwXamarin.Forms ライフサイクル
ライフサイクル
Xamarin.Forms 1.3において新しく刷新した、Xamarin.Forms.Applicationクラスには、次の3つのメソッドがオーバーライド可能になりました。OnStart アプリのスタート時
OnSleep アプリがバックグランド(スリープ状態)に移行した時
OnResume アプリがバックグランド(スリープ状態)から復帰した時
この動作について、詳細なレポートが@matatabi_uxさんの所で紹介されています。
Xamarin.Forms の App Lifecycle の呼び出され方を調べたい - しっぽを追いかけて
Xamarin.Forms の App Lifecycle の呼び出され方を調べたい 【Windows Phone 8.0 編】 - しっぽを追いかけて
Xamarin.Forms の App Lifecycle の呼び出され方を調べたい 【iOS編】 - しっぽを追いかけて
Xamarin.Forms の App Lifecycle の呼び出され方を調べたい 【Android 編】 - しっぽを追いかけて
上記のページで、全然、完璧なのですが、もともとiOSやAndroidのライフサイクルについて知識の乏しい私が理解するにはちょっと重たかったので・・・
完全真似っこですが、私なりに確かめてみました。
動作確認用のコード
動作確認のために書いたコードは下記の通りです。
ナビゲーションページをルートとして1ページ目をライム色、2ページ目をピンク色にしました。
また、1ページ目には、2ページ目に移動するボタンと、ブラウザを開くボタンを配置しました。
通過したメソッドを確認するためには、Appクラスに、呼び出し元のクラス名及びメソッド名を出力するLog()を作成し、オーバライドした各メソッドからこれを呼び出すようにしました。
//App.cs namespace App1{ public class App : Application{ public App(){ //NavigationPageの上に最初のページを構築する MainPage = new NavigationPage(new TopPage()); } protected override void OnStart(){ Log();//ログ出力 } protected override void OnSleep(){ Log();//ログ出力 } protected override void OnResume(){ Log();//ログ出力 } //呼び出し元のメソッド名を出力のする 「クラス名.メソッド名()」の形式 public static void Log([CallerFilePath] string file = "", [CallerMemberName] string member = ""){ Debug.WriteLine(string.Format("{0}.{1}()", Path.GetFileNameWithoutExtension(file).Split('\\').LastOrDefault(), member)); } } }
//最初のぺージ TopPage.cs namespace App1{ class TopPage : ContentPage{ public TopPage(){ BackgroundColor = Color.Lime;//背景色(ライム) //次ぼページ(SecondPage)を開くボタン var button1 = new Button{ Text = "Next", Command = new Command(async () =>{ await Navigation.PushAsync(new SecondPage()); }) }; //ブラウザを開くボタン var button2 = new Button{ Text = "Browser", Command = new Command(() =>{ Device.OpenUri(new Uri("http://xamarin.com/")); }) }; //2つのボタンを上下に配置する Content = new StackLayout{ Children = { button1, button2 } }; } protected override void OnAppearing(){ App.Log();//ログ出力 base.OnAppearing(); } } }
//2つ目のページ SecondPage.cs namespace App1{ class SecondPage : ContentPage{ public SecondPage(){ BackgroundColor = Color.Pink;//背景色(ピンク) } protected override void OnAppearing(){ App.Log();//ログ出力 base.OnAppearing(); } } }
Androidでの実行画面 |
iOSでの実行画面 |
WindowsPhoneでの実行画面 |
iOSによる動作確認
AppDelegate.csでも、各メソッドをオーバーライドしてLog()をコールしました。
namespace App1.iOS{ [Register("AppDelegate")] public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate{ public override bool FinishedLaunching(UIApplication app, NSDictionary options){ global::Xamarin.Forms.Forms.Init(); LoadApplication(new App()); App.Log();//ログ出力 return base.FinishedLaunching(app, options); } public override void FinishedLaunching(UIApplication application) { App.Log();//ログ出力 base.FinishedLaunching(application); } ・・・省略・・・
アプリ起動
AppDelegate.WillFinishLaunching() //起動時に呼び出される
AppDelegate.FinishedLaunching() //はじめての起動時に呼び出される
App.OnStart()
AppDelegate.OnActivated() // アクティブ化
TopPage.OnAppearing() // 表示
ページ遷移
SecondPage.OnAppearing()// 表示
ページ復帰
TopPage.OnAppearing()// 表示
ブラウザ起動
AppDelegate.OnResignActivation() //アプリが非Activeになる直前に呼び出される
App.OnSleep()
AppDelegate.DidEnterBackground() //アプリが非Activeになりバックグランド実行になった際に呼び出される
ホーム
AppDelegate.OnResignActivation() //アプリが非Activeになる直前に呼び出されるApp.OnSleep()
AppDelegate.DidEnterBackground() //アプリが非Activeになりバックグランド実行になった際に呼び出される
タスクリストからの起動
AppDelegate.WillEnterForeground()App.OnResume()
AppDelegate.OnActivated()
タスクリストへの移行
AppDelegate.OnResignActivation() //アプリが非Activeになる直前に呼び出されるApp.OnSleep()
アプリ終了
AppDelegate.DidEnterBackground() //アプリが非Activeになりバックグランド実行になった際に呼び出されるAppDelegate.WillTerminate() //システムからのアプリ終了の際に呼び出される
Androidによる動作確認
MainActivity.csでも、各メソッドをオーバーライドしてLog()をコールしました。
namespace App1.Droid{ [Activity(Label = "App1", Icon = "@drawable/icon", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)] public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsApplicationActivity{ protected override void OnCreate(Bundle bundle){ base.OnCreate(bundle); global::Xamarin.Forms.Forms.Init(this, bundle); LoadApplication(new App()); App.Log();//ログ出力 } protected override void OnStart() { App.Log();//ログ出力 base.OnStart(); } protected override void OnRestoreInstanceState(Bundle savedInstanceState) { App.Log();//ログ出力 base.OnRestoreInstanceState(savedInstanceState); } ・・・省略・・・
アプリ起動
App.OnStart()MainActivity.OnCreate()
MainActivity.OnStart()
MainActivity.OnPostCreate()
MainActivity.OnResume()
MainActivity.OnPostResume()
TopPage.OnAppearing()
ページ遷移
SecondPage.OnAppearing()ページ復帰
TopPage.OnAppearing()ブラウザ起動
MainActivity.OnUserLeaveHint()MainActivity.OnPause()
MainActivity.OnSaveInstanceState()
MainActivity.OnStop()
App.OnSleep()
ブラウザからの復帰
MainActivity.OnRestart()App.OnResume()
MainActivity.OnStart()
App.OnResume()
MainActivity.OnResume()
MainActivity.OnPostResume()
ホーム
MainActivity.OnUserLeaveHint()MainActivity.OnPause()
MainActivity.OnSaveInstanceState()
MainActivity.OnStop()
App.OnSleep()
タスクリストからの起動
MainActivity.OnRestart()
App.OnResume()
MainActivity.OnStart()
App.OnResume()
MainActivity.OnResume()
MainActivity.OnPostResume()
タスクリストへの移行
ログなし(おそらくこの時点ではActive)
アプリ終了
ログなし(既にHomeに遷移した時点でOnStopとなっているから)
サンプル
Xamarin.FormsでListViewのコンテキストアクションを使用するには?
BuildInsiderで連載されている「Xamarin逆引きTips」に寄稿させて頂きました。
Xamarin.FormsでListViewのコンテキストアクションを使用するには? - Build Insider
使用したコードは、下記にあります。
furuya02/XamarinTips.ContextActionsSample · GitHub
Xamarin.Formsでビヘイビアーを使用するには?
BuildInsiderで連載されている「Xamarin逆引きTips」に寄稿させて頂きました。
Xamarin.Formsでビヘイビアーを使用するには? - Build Insider
使用したコードは、下記にあります。
furuya02/XamarinTips.BehaviorSample · GitHub
Xamarin.Formsで地図の現在位置やピンの表示、縮尺や地図タイプの変更を行うには?(Xamarin.Forms.Maps使用)
BuildInsiderで連載されている「Xamarin逆引きTips」に寄稿させて頂きました。
Xamarin.Formsで地図の現在位置やピンの表示、縮尺や地図タイプの変更を行うには?(Xamarin.Forms.Maps使用) - Build Insider
使用したコードは、下記にあります。
furuya02/XamarinTips.MapsSample · GitHub
Xamarin.Formsで地図を表示するには?(Xamarin.Forms.Maps使用)?
BuildInsiderで連載されている「Xamarin逆引きTips」に寄稿させて頂きました。
Xamarin.Formsで地図を表示するには?(Xamarin.Forms.Maps使用) - Build Insider
使用したコードは、下記にあります。
furuya02/XamarinTips.MapsSample · GitHub
Xamarin.Forms NavigationPageでアクションバーのアイコンを非表示にする(Android)
アクションバーのアイコン
Xamarin.FormsでNavigationPageを使用すると、Androidでは、ページの左上にアイコンが表示されます。
このアイコンの消す方法は、Xamarin.Formsの機能としては提供されておらず、力づくなら、背景色に紛れた1ドットのアイコンなどに置き換えるしかないようです。
今回は、NavigationPageのレンダラーを記述して、正規に(?)、このアイコンを非表示にする方法が、Xamarinのフォーラムで紹介されていたので、ここに記録しました。
NavigationPage
NavigationPageを使用したPCL側のコードです。
レンダラー記述のためだけにNavigationPageの拡張クラス(ExNavigationPage)を作成しています。
//App.cs using Xamarin.Forms; namespace App1{ public class App : Application{ public App(){ //ルートビューをNavigationPageにする MainPage = new ExNavigationPage(new MainPage()); } //・・・省略・・・ } //拡張NavigationPage レンダラのためだけのクラス public class ExNavigationPage : NavigationPage { public ExNavigationPage(Page root) : base(root) {} } class MainPage : ContentPage { public MainPage() { //中央にラベル「MainPage」を配置する Content = new StackLayout { VerticalOptions = LayoutOptions.Center, Children = { new Label { XAlign = TextAlignment.Center, Text="MainPage" } } }; } } }
レンダラー
レンダラー側のコードは、次のようになります。
NavigationRendererクラスの、ContextプロパティがActivityクラスなので、そこからActionBarオブジェクトへたどれます。
ActionBarオブジェクトのSetIconメソッドで、Android.Resource.Color.Transparentを指定すると、アイコンは非表示になります。
//ExNavigationPageRenderer.cs using Android.App; using Xamarin.Forms; using Xamarin.Forms.Platform.Android; [assembly: ExportRenderer(typeof(ExNavigationPage), typeof(ExNavigationPageRenderer))] namespace App1.Droid{ class ExNavigationPageRenderer : NavigationRenderer{ protected override void OnElementChanged(ElementChangedEventArgs<NavigationPage> e) { base.OnElementChanged(e); var actionBar = ((Activity)Context).ActionBar; actionBar.SetIcon(Android.Resource.Color.Transparent); } } }
ActionBarオブジェクトのメソッドである、SetDisplayShowHomeEnabledやSetDisplayShowTitleEnabledは、この場合、有効に機能しません。
//このコードで、アイコンの非表示やタイトルバーの非表示はできない actionBar.SetDisplayShowHomeEnabled(false); actionBar.SetDisplayShowTitleEnabled(false);
参考資料
Remove icon from action bar from xamarin forms android project - Xamarin Forums
xml - Remove icon/logo from action bar on android - Stack Overflow