モチベーションも大事だと思うので覚書として使用します。
二週目感想
#準備
- VisualStudio(Xamarin)とAndroid実機(Digno)+接続端子
- PCでAndroidに合うUSBドライバをDL
- VSでツール>AndroidSDKマネージャー>実機OSverに合うSDKをDL(実機の端末情報で確認する)
- Androidでデベロッパー、USBデバッグ、ワイヤレス認証をON
#作成
- 新規プロジェクト>モバイルアプリ(名称:Phoneword)作成
- .Androidのプロパティ>アプリケーション>ターゲット>実機に合わせる
- .Androidのプロパティ>マニフェスト>ターゲット>SDKバージョン使用したコンパイルの使用
- 一旦そのままビルドして正常ならOK!
#編集
オブジェクト(ボタン)設置(.xaml)
構文詳細
<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Phoneword.MainPage">
<ContentPage.Padding>
<OnPlatform x:TypeArguments="Thickness">
<On Platform="iOS" Value="20, 40, 20, 20" />
<On Platform="Android, UWP" Value="20" />
</OnPlatform>
</ContentPage.Padding>
<StackLayout>
<Label Text="Enter a Phoneword:" />
<Entry x:Name="phoneNumberText" Text="1-855-XAMARIN" />
<Button x:Name="translateButon" Text="Translate" Clicked="OnTranslate" />
<Button x:Name="callButton" Text="Call" IsEnabled="false" Clicked="OnCall" />
</StackLayout>
</ContentPage>
オブジェクトの条件定義(xaml.cs)
構文詳細
`InitializeComponent ();`名前付の再利用可能なインスタンス(下記翻訳と通話ボタン定義)(App.xaml.csに てここで定義された情報を使用する。必須のメソッド) このApp.xaml.csとはActivityのライフサイクルのクラス←このサイクル理解してないと編集できない、アプリやってて縦画面のアプリを横画面にしたら止まったり変な画面なるのはこのせい! [一番分かりやすかった解説と図解](http://tatete.blogspot.com/2012/01/activity.html)
using System;
using Xamarin.Forms;
namespace Phoneword
{
public partial class MainPage : ContentPage
{
string translatedNumber;
public MainPage ()
{
InitializeComponent ();
}
void OnTranslate (object sender, EventArgs e)
{
translatedNumber = PhonewordTranslator.ToNumber (phoneNumberText.Text);
if (!string.IsNullOrWhiteSpace (translatedNumber)) {
callButton.IsEnabled = true;
callButton.Text = "Call " + translatedNumber;
} else {
callButton.IsEnabled = false;
callButton.Text = "Call";
}
}
async void OnCall (object sender, EventArgs e)
{
if (await this.DisplayAlert (
"Dial a Number",
"Would you like to call " + translatedNumber + "?",
"Yes",
"No")) {
var dialer = DependencyService.Get<IDialer> ();//各プラで生成したインスタンス呼出
if (dialer != null)//実行結果条件
dialer.Dial (translatedNumber);//条件2
}
}
}
}
オブジェクトのクラス追加と定義(.cs)
構文詳細
翻訳ボタンについて(英字を電話番号に変換)PhoneTranslator.cs
using System.Text;
namespace Phoneword
{
public static class PhonewordTranslator
{
public static string ToNumber(string raw)
{
if (string.IsNullOrWhiteSpace(raw))
return null;
raw = raw.ToUpperInvariant();
var newNumber = new StringBuilder();
foreach (var c in raw)
{
if (" -0123456789".Contains(c))
newNumber.Append(c);
else
{
var result = TranslateToNumber(c);
if (result != null)
newNumber.Append(result);
// Bad character?
else
return null;
}
}
return newNumber.ToString();
}
static bool Contains(this string keyString, char c)
{
return keyString.IndexOf(c) >= 0;
}
static readonly string[] digits = {
"ABC", "DEF", "GHI", "JKL", "MNO", "PQRS", "TUV", "WXYZ"
};
static int? TranslateToNumber(char c)
{
for (int i = 0; i < digits.Length; i++)
{
if (digits[i].Contains(c))
return 2 + i;
}
return null;
}
}
}
オブジェクトのクラス追加とinterface定義(.cs)
構文詳細
namespace Phoneword
{
public interface IDialer//インターフェイス定義
{
bool Dial(string number);インターフェイス定義
}
}
以上、共通プロジェクト(オブジェクトとinterface定義完了これでDependencyService実装可能)
|>━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━<|
以下、interface継承しiOSとAndroidにDependencyService(iDialer)登録、定義
iOSにiDialerのクラス追加と継承と定義(.cs)
構文詳細
using Foundation;
using Phoneword.iOS;
using UIKit;//
using Xamarin.Forms;
[assembly: Dependency(typeof(PhoneDialer))]
namespace Phoneword.iOS
{
public class PhoneDialer : IDialer//先程定義したinterface IDialer実装
{
public bool Dial(string number)
{
return UIApplication.SharedApplication.OpenUrl (
new NSUrl ("tel:" + number));
}
}
}
AndroidにiDialerのクラス追加と継承と定義(.cs)[LinQ intent DI詳細]
構文詳細
※ついでに(アプリが電話かけるアクセス許可)Phoneword.Android
のプロパティ>マニフェスト>アクセス許可>CALL_PHONE
LinQとは
※URIはURLとURNの総称(URNは永続的
intentとは
※アクティビティは画面、UIの上の階層表現、Androidにおけるクラスの1つ
メイン画面から次画面に移る(=メインアクティビティから次のアクティビティへと遷移する)
クラスとしてのActivityは色々な用途に使われているためなるべくFragmentで複数張り付けが望ましい。
var intent=new intent(intent.アクション);
intent.SetData("識別キー")+値;
context.StartActivity*(intent);
return true/false
例1// Intent のインスタンス(値まで入れた実体クラス)を生成。
この時の第二引数に遷移先のクラス(.csの)を渡す
var intent = new Intent(this,typeof(Activity1));
// StartACtivity メソッドを使いインテントを起動する。
StartActivity(intent);
例2Intent intent = new Intent(Settings.ACTION_DEVICE_INFO_SETTINGS);
startActivity(intent);
例3Intent intent = new Intent(AlarmClock.ACTION_SHOW_ALARMS);
startActivity(intent);
今回の例
[assembly: Dependency(typeof(PhoneDialer))]
namespace Phoneword.Droid
{
public class PhoneDialer : IDialer
{
public bool Dial(string number)
{
var context = MainActivity.Instance;
if (context == null)
return false;
var intent = new Intent (Intent.ActionDial);
intent.SetData (Uri.Parse ("tel:" + number));//setして(”識別キー”+値)
if (IsIntentAvailable (context, intent)) {
//setされた値はUriに変換されcontext, intentになる、それがAvailable(有効)なら実行
context.StartActivity (intent);//実行
return true;//true
}
return false;//それ以外全部false
}
DependencyInjection(依存注入)とは
using Android.Content;//DBにデータを取得/保存する時に利用するクラス
using Android.Telephony;//アクセス情報/電話情報を監視/操作できるAPI
using Phoneword.Droid;
using System.Linq;//言語統合型クエリLanguage-Integrated(言語が統合された) Query(問い合わせ)
using Xamarin.Forms;
using Uri = Android.Net.Uri;//Android.NetクラスライブラリのUriクラス
[assembly: Dependency(typeof(PhoneDialer))]//メタデータ登録 継承
namespace Phoneword.Droid
{
public class PhoneDialer : IDialer
{
public bool Dial(string number)//Intentここから 定義
{
var context = MainActivity.Instance;
if (context == null)
return false;
var intent = new Intent (Intent.ActionDial);
intent.SetData (Uri.Parse ("tel:" + number));
if (IsIntentAvailable (context, intent)) {
context.StartActivity (intent);
return true;
}
return false;
}//intentここまで
public static bool IsIntentAvailable(Context context, Intent intent)
{
var packageManager = context.PackageManager;
var list = packageManager.QueryIntentServices (intent, 0)
.Union (packageManager.QueryIntentActivities (intent, 0));
if (list.Any ())
return true;
var manager = TelephonyManager.FromContext (context);
return manager.PhoneType != PhoneType.None;
}
}
}
Androidのメインアクティビティに`instance`追加(.Android\MainActivity.cs)
構文詳細
mipmap/iconをマニフェストに登録
スタートアップ プロジェクトに登録
デバイス名 ▷←この三角ボタンで実行テスト
グローバル名前空間とは
public class MyClass { //グローバル名前空間内のクラス
public void MyMethod() {
//////////
}
}
namespace MyNamespace { // グローバル名前空間内の名前空間
public class MyClass {
public void MyMethod() {
//////////
}
}
}
- instansプロパティ追加のため編集を行ったがiOSでは特に必要ない。
- チュートリアルでも記述なし、ちなみに最下行の保存は誤翻訳。
- XmarinでMainActivity作成について質問
- 具体的にMainActivityはMainActivity内はthisで取得、DepandencyServiceMainActivityを取得するには、MainActivityのOnCreateでstatic(クラス外呼出可能な)なグローバル変数にセット
- 1行で呼び出す方法もあるらしいインスタンスを取得する方法
using Android.App;
using Android.Content.PM;
using Android.OS;
namespace Phoneword.Droid
{
[Activity(Label = "Phoneword", Icon = "@mipmap/icon", Theme = "@style/MainTheme", MainLauncher = true,
ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity//global::~が
{
internal static MainActivity Instance { get; private set; }
protected override void OnCreate(Bundle bundle)
{
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
base.OnCreate(bundle);
Instance = this;
global::Xamarin.Forms.Forms.Init(this, bundle);
LoadApplication(new App());
}
}
}
一旦割愛UWPにオブジェクトのクラス追加と継承と定義(.cs)
構文詳細
Phoneword.UWP
にクラスPhoneDialer.cs
追加
using Phoneword.UWP;
using System;
using System.Threading.Tasks;
using Windows.ApplicationModel.Calls;
using Windows.UI.Popups;
using Xamarin.Forms;
[assembly: Dependency(typeof(PhoneDialer))]
namespace Phoneword.UWP
{
public class PhoneDialer : IDialer
{
bool dialled = false;
public bool Dial(string number)
{
DialNumber(number);
return dialled;
}
async Task DialNumber(string number)
{
var phoneLine = await GetDefaultPhoneLineAsync();
if (phoneLine != null)
{
phoneLine.Dial(number, number);
dialled = true;
}
else
{
var dialog = new MessageDialog("No line found to place the call");
await dialog.ShowAsync();
dialled = false;
}
}
async Task<PhoneLine> GetDefaultPhoneLineAsync()
{
var phoneCallStore = await PhoneCallManager.RequestStoreAsync();
var lineId = await phoneCallStore.GetDefaultLineAsync();
return await PhoneLine.FromIdAsync(lineId);
}
}
}
#結果
-
iOS関連エラーだけで問題無さげな感じになりました。
-
iOSはLivePlayerがサポートやめ今後もない&代わりのエミュもMac必須なので次は別の方法(DevOps)でテストしてみたいと思います。
-
App CenterとVSTSの統合でDevOpsとして利用でき、これにより①boardsでタスク管理②Pipelinesでクラウド上のOSでビルド・テスト③reposでレポジトリ管理できるようなり使い分け必要なくなった。githubもMS買収)
-
MSのDevOps一択になりそうなので、これでまた準備~実行までしたいと思います。
-
流れは把握したがまだ学習してない演算子やアクティビティのライフサイクルの理解の必要が出てきて、特に最後のアクティビティについてコード内最初の[Activityも、最後のglobal::も、最終的にInstanceプロパティにthisを何故代入したかったのか(これはMainActivity.cs編集だが画面作成と関係ない)を理解できないので次回のXmarin学習で解決したい。