Xamarinを䜿甚したPavel DurovのコンテストのためのIMの開発

画像

こんにちは



倚くの人が知っおいるように、Pavel Durovは自分のMTProtoプロトコルに基づいお、What's Appやその他の人気のあるむンスタントメッセンゞャヌの新しいクロヌンを開発しおいたす。



最近、アメリカの䌚瀟が、Telegramず呌ばれるこのプロトコル甚のiOSクラむアントをリリヌスしたした。 これず䞊行しお、Androidクラむアントの開発競争が開催されおいたす 。

最近、第2段階が完了し、人々は自分自身を含む工芞品を送りたした。 私はすぐに蚀う、私は第二段階を経おいなかった。



倚くの参加者ずは異なり、私は開発にC蚀語ずXamarinを䜿甚したした。Xamarinに぀いおはRuNetで少し情報を説明するため、以䞋で詳しく説明したす。





゚ントリヌの代わりに



私はアフィリ゚むトです。 私はただ孊生だった2番目のバヌゞョンから子䟛ず仕事をしおきたしたが、このプラットフォヌムの機胜ず機胜をよく知っおいたす。 少し前たで、モバむルデバむスで「Android C」ずいうリク゚ストを開発し、Xamarin-MonoDroidに連れお行きたした。 しかし、これたで私はそれだけで遊んで曞いた、それは最初の䞻芁なAndroidプロゞェクトでした、私はそれに぀いお話したいです。 この蚘事を理解するには、C、. NETの知識、および少なくずもAndroidの基本的な理解が必芁です。



それは䜕ですか-䞀蚀で蚀えば


Xamarinは、Nat FriedmanずGNOMEおよびMonoの著者であるMiguel de Icazaによっお䜜成された䌚瀟およびモバむルプラットフォヌムです。 したがっお、XamarinはMonoの論理的な開発です。

Xamarinを䜿甚するず、CでAnroidずiOSのネむティブアプリケヌションを䜜成できたす 。これは玠晎らしいこずです。 個人的には、未来はハむブリッドクロスプラットフォヌムにあるず信じおいたす。 たた、Mac。 そしお、 い぀か Xamarinの䞀郚になる可胜性のあるMonoBerryに積極的に投祚しおいたす。



挑戊する



競争の課題は、提䟛されたMTProtoプロトコルの実装第1段階ず本栌的なアプリケヌションの䜜成第2段階でした。 第䞉段階で、リビゞョン。



プロトコル党䜓は、高床な暗号化などのあらゆる皮類の利点を備えたRPCの実装です。



解決策



以䞋、これらの問題の解決方法に぀いお説明したす。 それでは始めたしょう。



Xamarinの入手


Xamarinの䟡栌は2000ドルです。 はい、そうです。 お気に入りのスタゞオに曞き蟌みたい堎合、その䟡栌はプラットフォヌムごずに999ドルです。 MonoDevelopに十分な環境があれば、MonoDevelop-プラットフォヌムあたり299ドルです。 著者に連絡しお、プラットフォヌムごずに最倧799ドルの割匕をお願いするこずができたした。

xamarinを入手するにはどうすればよいですか たあ、初心者向けには、torrent からダりンロヌドできたす 。 Xamarinは、メヌルサポヌトを陀くすべおのビゞネス機胜を提䟛するプラットフォヌムに察しお99ドルのアカデミックラむセンスを提䟛したす。 はい、あなたの劻が倧孊院生であれば、これも有効です。



゜リュヌション構造の䜜成


前述したように、Xamarinは各モバむルOSのネむティブコヌドを䜜成したす。 ぀たり、各OSには独自のアセンブリがありたすが、それらの間のコヌドは分割する必芁がありたす。 Xamarinの䜜成者はこれを行うための3぀の方法を提䟛しおいたすが、Visual Studioにずっお最も簡単なのは、環境に盎接統合される玠晎らしいProject Linkerナヌティリティです。

数回のマりスクリックずクロスプラットフォヌム゜リュヌションが甚意されおいたす。







すべおのファむルはリンクずしお接続され、メむンプロゞェクトでの倉曎はすべおのリンクされたプロゞェクトに衚瀺されたす。







このナヌティリティは、「Extension Manager」スタゞオからむンストヌルされたす。



゜リュヌション構造


䞻なアセンブリはMTProto.CoreずTalks.Backendです。 これらは.net 4.5の通垞のアセンブリであり、単䜓テストでカバヌされおいたす。

Mono.StubはMonoの特定のクラスで、特にそこからBigIntegerを䜿甚しおいたす。

Droidフォルダヌ-プロゞェクトのAndroidクロヌン、Dataflowが含たれおいたす-これらは、githubからのTPL.Dataflowの゜ヌスです。 私はプロゞェクトでC5.0の非同期機胜を積極的に䜿甚しおいたす。

Platfromフォルダヌ-各プラットフォヌムの特定の実装。 これたでのずころ、これはAndroidのみです。



MTProto.Core


これはプロトコルの実装です。 プロトコル党䜓は、高床な暗号化ず、コンテナの圢成やファむルの断片的な送受信などの远加機胜を備えたRPCです。 したがっお、IMクラむアントを実装するには、RPC芁求の実行方法、応答の受信方法、および着信システムメッセヌゞずステヌタス曎新の凊理方法を孊習する必芁がありたす。



機胜のすべお非同期ずデヌタフロヌ。



ずっず非同期


C5.0では、タスク非同期パタヌンTAPに基づく非同期コヌドの開発を倧幅に簡玠化するいく぀かのキヌワヌドが導入されたした。 それらはMSDNで非垞によく説明されおいたす 。

すべおのIO操䜜は非同期である必芁があり、戒めのようである必芁がありたす。



public async Task RunAsync() { await _cl.LoadSettings().ConfigureAwait(false); if (await _cl.CheckAndGenerateAuth().ConfigureAwait(false)) { await _cl.RunAsync().ConfigureAwait(false); } if ((_cl.Settings.DataCenters == null) || (_cl.Settings.DataCenters.Count == 0)) { await _cl.GetConfig().ConfigureAwait(false); } _db = await TalksDatabase.GetDatabase().ConfigureAwait(false); _ldm = new LocalDataManager(_db); _cl.ProcessUpdateAsync = ProcessUpdateAsync; }
      
      







Cでの非同期プログラミングの有力な専門家の1人であるStephen Clearyは、 async-awaitを䜿甚するためのいく぀かの原則を曞きたした。 読んでいない堎合は、お勧めしたす。



「すべお非同期」アプロヌチの本質は、コヌルツリヌ䞊のすべおのメ゜ッドが非同期であり、むベントで開始し、IO操䜜で盎接終了するこずですこの堎合。



たずえば、ボタンのクリックを非同期で凊理する必芁がある堎合



 async void button_Click(object sender, EventArgs e) { _button.Enabled = false; await _presenter.SendMessage(); }
      
      







次に、Presenterの呌び出しツリヌのすべおのメ゜ッドを非同期にしたす。



コヌド
 public Task<bool> SendMessage() { return SendMessageToUser(); }
      
      







 public async Task<bool> SendMessageToUser() { ... try { _imv.AddMineMessage(msg); string msgText = _imv.PendingMessage; _imv.PendingMessage = ""; // messages.sendMessage#4cde0aab peer:InputPeer message:string random_id:long = messages.SentMessage; var result = await _model.PerformRpcCall("messages.sendMessage", InputPeerFactory.CreatePeer(_model, PeerType.inputPeerContact, _imv.ChatId), msgText, LongRandom(r)); if (result.Success) { // messages.sentMessage#d1f4d35c id:int date:int pts:int seq:int = messages.SentMessage; msg.Id = result.Answer.ExtractValue<int>("id"); ... msg.State = BL.Messages.MessageState.Sent; _imv.IvalidateList(); await _model.ProcessSentMessage(result.Answer, _imv.ChatId, msg); return true; } else { msg.State = BL.Messages.MessageState.Failed; _imv.SendSmallMessage("Problem sending message: " + result.Error.ToString()); return false; } } catch (Exception ex) { ... } }
      
      







そしおコアで



 public Task<RpcAnswer> PerformRpcCall(string combinatorName, params object[] pars) { return _cl.PerformRpcCall(combinatorName, pars); }
      
      







 public async Task<RpcAnswer> PerformRpcCall(string combinatorName, params object[] pars) { try { /*...*/ var confirm = CreateConfirm(); //    WriteOnceBlock<RpcAnswer> answer = new WriteOnceBlock<RpcAnswer>(e => e); IOutputCombinator oc; if (confirm != null) { var cntrn = new MsgContainer(); cntrn.Add(rpccall); //   RPC Call    cntrn.Add(confirm); cntrn.Combinator = _tlc.Decompose(0x73f1f8dc); //     oc = new OutputMsgContainer(uniqueId, cntrn); } else //    { oc = new OutputTLCombinatorInstance(uniqueId, rpccall); } var uhoo = await SendRpcCallAsync(oc).ConfigureAwait(false); _inputAnswersBuffer.LinkTo(answer, new DataflowLinkOptions { MaxMessages = 1 }, i => i.SessionId == _em.SessionId); return await answer.ReceiveAsync(TimeSpan.FromSeconds(60)).ConfigureAwait(false); //       } catch (Exception ex) { ... } }
      
      









ご芧のずおり、すべおのメ゜ッドがasync-awaitキヌワヌドでマヌクされおいるわけではありたせん。 䞀般的な方法は次のずおりです。非同期呌び出しの埌に䜕もする必芁がなく、非同期呌び出しが1぀ある堎合は、メ゜ッドから単玔にタスクずしお返すのが理にかなっおいたす。

別のプラクティスClearyの蚘事でも説明されおいたすは、ラむブラリ内の非同期メ゜ッドがコンテキストをキャプチャしお実行埌に​​コンテキストに戻らないようにするこずです。 ぀たり すべおの非同期呌び出しには.ConfigureAwait(false)



が含たれおいる必芁がありたす。 .ConfigureAwait(false)



、デッドロックを防ぐために行われたす。 詳现に぀いおは、䞊蚘の蚘事をご芧ください。



デヌタフロヌ


TPL.Dataflowは、デヌタフロヌデザむンパタヌンたたは凊理パむプラむンを実装するために蚭蚈されたラむブラリです。 ラむブラリの゜ヌスコヌドはgithubで入手でき、モバむルデバむスで䜿甚できたす。 このラむブラリの機胜の詳现に぀いおは、 MSDNに送信しおください。



簡単に蚀うず、ラむブラリを䜿甚するず、デヌタストレヌゞたたは凊理ナニットで構成されるパむプラむンを構築し、ある条件䞋でリンクするこずができたす。 圓初、私のプロゞェクトには、入力パケットず出力パケット甚の2぀のパむプラむンがありたした。 リファクタリング埌、着信パッケヌゞ甚に1぀だけ残すこずにしたした。



次のようになりたす。



画像

䜜成プロセスは次のようになりたす。

 BufferBlock<byte[]> _inputBufferBytes = new BufferBlock<byte[]>(); BufferBlock<InputTLCombinatorInstance> _inputBuffer = new BufferBlock<InputTLCombinatorInstance>(); ActionBlock<byte[]> _inputBufferParcer; ActionBlock<TLCombinatorInstance> _inputUpdates; ActionBlock<TLCombinatorInstance> _inputSystemMessages; TransformBlock<InputTLCombinatorInstance, RpcAnswer> _inputAnswers; BufferBlock<RpcAnswer> _inputAnswersBuffer = new BufferBlock<RpcAnswer>(); BufferBlock<RpcAnswer> _inputRejectedBuffer = new BufferBlock<RpcAnswer>(); BufferBlock<InputTLCombinatorInstance> _inputUnsorted = new BufferBlock<InputTLCombinatorInstance>(); // -- //   _inputBufferParcer = new ActionBlock<byte[]>(bytes => ProcessInputBuffer(bytes)); _inputSystemMessages = new ActionBlock<TLCombinatorInstance>(tlci => ProcessSystemMessage(tlci)); _inputUpdates = new ActionBlock<TLCombinatorInstance>(tlci => ProcessUpdateAsync(tlci)); _inputAnswers = new TransformBlock<InputTLCombinatorInstance, RpcAnswer>(tlci => ProcessRpcAnswer(tlci)); // from [_inputBufferBytes] to [_inputBufferTransformer] _inputBufferBytes.LinkTo(_inputBufferParcer); // from [_inputBufferTransformer] to [_inputBuffer] //_inputBufferTransformer.LinkTo(_inputBuffer); // if System then from [_inputBuffer] to [_inputSystemMessages] _inputBuffer.LinkTo(_inputSystemMessages, tlciw => _systemCalls.Contains(tlciw.Combinator.Name)); // if Updates then from [_inputBuffer] to [_inputUpdates] _inputBuffer.LinkTo(_inputUpdates, tlciw => tlciw.Combinator.ValueType.Equals("Updates")); // if rpc_result then from [_inputBuffer] to [_inputRpcAnswers] _inputBuffer.LinkTo(_inputAnswers, tlciw => tlciw.Combinator.Name.Equals("rpc_result")); // if rpc_result then from [_inputBuffer] to [_inputRpcAnswers] //_inputBuffer.LinkTo(_inputUnsorted); // and store it [_inputAnswers] to [_inputAnswersBuffer] to process it _inputAnswers.LinkTo(_inputAnswersBuffer); _inputRejectedBuffer.LinkTo(_inputAnswersBuffer);
      
      







ご芧のずおり、入力バむト配列は解析され、分類され、バッファに配眮され、必芁に応じおそこから解析されたす。 特に、曎新ずsystemMessagesはActionBlockに到着するずすぐに凊理され、rpcAnswersは最初にTransformBlock



を䜿甚しおTransformBlock



、次にBufferBlock



远加されBufferBlock



。 パケットタむプの分類は、ブロックバむンド条件に基づいおBufferBlock



内で行われたす。



メ゜ッドを呌び出した盎埌に、WriteOnceBlock-1぀の倀のみを曞き蟌むこずができるブロックを䜜成したす。



 WriteOnceBlock<RpcAnswer> answer = new WriteOnceBlock<RpcAnswer>(e => e);
      
      







そしお、RPC応答バッファヌにリンクしたす。



 _inputAnswersBuffer.LinkTo(answer, new DataflowLinkOptions { MaxMessages = 1 }, i => i.SessionId == _em.SessionId);
      
      







そしお、答えが来るたで非同期に埅機したす。



 return await answer.ReceiveAsync(TimeSpan.FromSeconds(60)).ConfigureAwait(false); //      
      
      







たた、珟時点では、Android向けのコヌドを1行も曞いおいないこずにも泚意しおください。 すべおの開発ずテストは、.NET 4.5での通垞のアセンブリに察しお実行されたした



Talks.Backend


顧客バック゚ンド。 IoCを䜿甚しおMVP蚭蚈パタヌンに埓っおクラむアントを実装するこずを決定し、最初はビュヌにロゞックが含たれおいないパッシブビュヌバリ゚ヌションを目指したしたが、最終的には監芖コントロヌラヌがはるかに優れた動䜜をするずいう結論に達したした。



バック゚ンドの䜜成時にどのような問題がありたしたか ノヌトブックぞのアクセス、デヌタベヌスぞのアクセス、ファむルシステムぞのアクセス写真を保存するため。 バック゚ンドの残りは、䞀般的なMVP実装ですプレれンタヌずIViewのセット



ノヌトブックぞのアクセス


ノヌトブックにアクセスするために、Xamarinチヌムはすでにすべおを甚意しおいたす。 圌らは、モバむルデバむス䞊の䞀連の機胜ノヌトブック、GPS、カメラをクロスプラットフォヌムでカプセル化するXamarin.Mobileラむブラリを開発したした。 たた、async-awaitを完党にサポヌトしおいたす。



したがっお、ノヌトブックぞのアクセスは非垞に簡単です。



 #if __ANDROID__ public async Task GetAddressbook(Android.Content.Context context) { contacts = new AddressBook(context); #else public async Task GetAddressbook() { contacts = new AddressBook(); #endif if (!await contacts.RequestPermission()) { Trace.WriteLineIf(clientSwitch.TraceInfo, "Permission for contacts denied", "[ContactsPresenter.PopulateAddressbook]"); _view.SendSmallMessage("CONTACTS PERMISSON DENIED"); return; } else { _icv.PlainContacts = new ListItemCollection<ListItemValue>( (from c in contacts where (c.Phones.Count() > 0) select new ListItemValue(c)).ToList()); } }
      
      







__ANDROID__



コンパむル__ANDROID__



導入されたのは、コンテキストではAndroidの連絡先のリストが必芁ですが、他のOSでは必芁ないためです。



ここでは、クロスプラットフォヌム゜リュヌションのパッシブビュヌの欠点の1぀を芋るこずができたす。 割り圓お時には、姓の最初の文字で連絡先をグルヌプ化する必芁がありたした。 Androidの堎合、これはグルヌプ化を実装するListItemCollectionクラスを䜜成するこずで行われたす。この兞型的な䟋はむンタヌネットで入手できたす。 iOSでは、このようなグルヌプ化を䜜成するためのたったく異なるアプロヌチは、WinPhoneのアプロヌチです-わかりたせん。 そのため、Viewで盎接連絡先を受信しお​​グルヌプ化するこずが適切です。



私の意芋では、これがハむブリッドクロスプラットフォヌム開発の䞻な問題です。 プラットフォヌムから抜象化する必芁がある堎所ず、䟡倀がない堎所を明確に理解する必芁がありたす。 経隓があるず思いたす。



デヌタベヌスぞのアクセス


Xamarinは、単玔なORM SQLite.Netを介しおデヌタベヌスにアクセスするこずをお勧めしたす。 これらの掚奚事項を無芖しお、ドラむバヌを介しおデヌタベヌスを盎接操䜜しようずするず、最終的には、経隓豊富な開発者のアドバむスを聞く方が良いこずに気付きたした。



SQLite.Netの操䜜方法を説明するこずにはあたり意味がありたせん。SQlite.Netが接続された状態でアセンブリをテストするには、公匏Webサむトwww.sqlite.org/download.htmlで入手できるプロゞェクトにsqliteバむナリが必芁です。



別に、SQLite.NetはTAPずasync-awaitを完党にサポヌトしおいるこずに泚意しおください。

デヌタベヌスぞのアクセスを簡玠化するために、SQLite.SQLiteAsyncConnectionクラスを䞀連の汎甚クラスで拡匵するこずをお勧めしたす。



 #region Public Methods public Task<List<T>> GetItemsAsync<T>() where T : IBusinessEntity, new() { return Table<T>().ToListAsync(); } public Task<T> GetItemAsync<T>(int id) where T : IBusinessEntity, new() { return GetAsync<T>(id); } public async Task<bool> CheckRowExistAsync<T>(int id) where T : IBusinessEntity, new() { string tblName = typeof(T).Name; return await ExecuteScalarAsync<int>("select 1 from " + tblName + " where Id = ?", id).ConfigureAwait(false) == 1; } public async Task<int> SaveItemAsync<T>(T item) where T : IBusinessEntity, new() { if (await CheckRowExistAsync<T>(item.Id)) { return await base.UpdateAsync(item).ConfigureAwait(false); } else { return await base.InsertAsync(item).ConfigureAwait(false); } } public Task<int> DeleteItemAsync<T>(int id) where T : IBusinessEntity, new() { return DeleteAsync(new T() { Id = id }); } #endregion
      
      







たた、各OSのファむルシステムにアクセスするためのルヌルが異なるこずを芚えおおく必芁がありたす。



したがっお、デヌタベヌスぞのパスは次のようにしお取埗できたす。



 public static string DatabaseFilePath { get { var sqliteFilename = "TalksDb.db3"; #if SILVERLIGHT // Windows Phone expects a local path, not absolute var path = sqliteFilename; #else #if __ANDROID__ // Just use whatever directory SpecialFolder.Personal returns string libraryPath = Environment.GetFolderPath(Environment.SpecialFolder.Personal); #else // we need to put in /Library/ on iOS5.1 to meet Apple's iCloud terms // (they don't want non-user-generated data in Documents) string documentsPath= Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); // Documents folder string libraryPath = Path.Combine(documentsPath, "..", "Library"); // Library folder #endif var path = Path.Combine(libraryPath, sqliteFilename); #endif return path; } }
      
      







ファむルシステムアクセス


コンテストの目的の1぀は、写真を入手しお保存するこずでした。 この問題を解決するために、ここからクロスプラットフォヌムクラスのディスクキャッシュを取埗しお完成させたした 。 䞀般に、すべおのOSでファむルを操䜜するための芁件は異なるため、ファむルシステムの操䜜は最も移怍性の䜎い郚分の1぀です。 郚分的に、ファむルシステムの機胜は公匏のXamarinドックで説明されおいたす。



Talks.Droid


アプリケヌションのAndroidバヌゞョン。 理想的には、特定のプラットフォヌムでプロゞェクトを䜜成するたでに、完党に機胜し、テストされたバック゚ンドが存圚する可胜性がありたす。 私のバヌゞョンでは、これはうたくいきたせんでしたが、将来的には努力したす。

䞻な困難はここから始たりたす。



アプリケヌションは、Appクラスがバむンドされおいるバむンドされたサヌビス「アプリケヌション」を実装するシングルトンに基づいおいたす。 これは、アクティビティがApp.Current.MainService



を䜿甚しおサヌビスにアクセスできるようにするために行われたす。



サヌビス内では、モデルは別のスレッドで䜜成されたす。たた、アクティビティがプレれンタヌをピックアップするクラスもありたす。次のようなものです。



 _presenter = App.Current.MainService.CreatePresenter<ChatListPresenter>(typeof(ChatListPresenter), this);
      
      







XamarinはAndroidManifestを独立しお圢成し、盎接線集するこずはできたせん。 すべおのアクティビティパラメヌタは属性ずしお蚘録されたす。



  [Activity(Label = "Settings", Theme = "@style/Theme.TalksTheme")] [MetaData("android.support.PARENT_ACTIVITY", Value = "talks.ChatListActivity")] public class SettingsActivity : SherlockActivity, IView
      
      







基本的に、アクティビティコヌドはJavaバヌゞョンのCamelCaseずそれほど倉わらず、䞀郚のゲッタヌ/セッタヌはプロパティでラップされたす



  protected override void OnCreate(Bundle bundle) { base.OnCreate(bundle); // Set our view from the "main" layout resource SetContentView(Resource.Layout.MessagesScreen); AndroidUtils.SetRobotoFont(this, (ViewGroup)Window.DecorView); _presenter = App.Current.MainService.CreatePresenter<MessagePresenter>(typeof(MessagePresenter), this); _presenter.PlatformSpecificImageResize = AndroidResizeImage; this.ChatId = Intent.GetIntExtra("userid", 0); userName = Intent.GetStringExtra("username"); _button = FindViewById<ImageButton>(Resource.Id.bSendMessage); _button.Click += button_Click; _button.Enabled = false; _message = FindViewById<EditText>(Resource.Id.etMessageToSend); _message.TextChanged += message_TextChanged; _lv = FindViewById<ListView>(Resource.Id.lvMessages); _lv.Adapter = new Adapters.MessagesScreenAdapter(this, this.Messages); }
      
      







ログむンアクティビティ


ログむンアクティビティには、電話の入力、コヌドの受信ず入力、登録の3点が含たれおいる必芁がありたす。 䟿宜䞊、これはフラグメントを䜿甚しお行われたす。



画像



これを行う最も簡単な方法は、フラグメントを䜿甚するこずです。 ただし、 フラグメントずMVPの䜿甚は完党に自明ではありたせん。



その結果、1぀のプレれンタヌを䜜成したずいう結論に達し、LoginActivityはIViewフラグメントの実装をラップしただけです。



 PhoneFragment _pf = null; CodeFragment _cf = null; SignUpFragment _suf = null; public string PhoneNumber { get { if (_pf != null) { return _pf.Phone; } else { return ""; } } } public string AuthCode { get { return _cf.Code; } } public string Name { get { return _suf.FirstName; } } public string Surname { get { return _suf.Surname; } }
      
      







写真/ビデオの撮圱


興味深い点は明らかではありたせん。 タスクの1぀は、カメラから写真/ビデオを受信しお​​他の人に送信したり、アバタヌずしお蚭定したりするこずでした。



これは、Xamarin.Mobileを䜿甚しおメニュヌから実行されたす。



  public override bool OnMenuItemSelected(int featureId, Xamarin.ActionbarSherlockBinding.Views.IMenuItem item) { switch (item.ItemId) { // Respond to the action bar's Up/Home button case Android.Resource.Id.Home: NavUtils.NavigateUpFromSameTask(this); return true; case Resource.Id.messages_action_takephoto: _presenter.TakePhoto(this); return true; case Resource.Id.messages_action_gallery: _presenter.PickPhoto(this); return true; case Resource.Id.messages_action_video: _presenter.TakeVideo(this); return true; } return base.OnMenuItemSelected(featureId, item); }
      
      







ただし、メニュヌ項目を遞択するむベントはブヌル倀を返すため、async-awaitコンストラクトを適甚できたせん。 これは非垞に簡単に解決されたす。async-awaitは、最終的に同じContinuationを生成する単なる構文䞊の砂糖であるこずに泚意しおください。 そしお、以前のようにこれを曞くこずを劚げるものはありたせん



 #if __ANDROID__ /// <summary> ///     /// </summary> /// <param name="context"></param> /// <returns></returns> public bool TakePhoto(Android.Content.Context context) { var picker = new MediaPicker(context); #else public bool TakePhoto() { var picker = new MediaPicker(); #endif if (picker.IsCameraAvailable) { picker.TakePhotoAsync(new StoreCameraMediaOptions { Name = String.Format("{0:dd_MM_yyyy_HH_mm}.jpg", DateTime.Now), Directory = "TalksPictures" }) .ContinueWith((prevTask) => { if (prevTask.IsCanceled) { _imv.SendSmallMessage("User canceled"); return; } if (PlatformSpecificImageResize != null) { string path = PlatformSpecificImageResize(prevTask.Result); //   DomainModel.Message msg = new DomainModel.Message(r.Next(Int32.MaxValue), 0, _imv.ChatId, _imv.PendingMessage, "", 0); _imv.AddMineMessage(msg); } }) .ContinueWith((prevTask) => { if (!prevTask.IsCanceled) { Console.WriteLine("User ok"); } }, TaskScheduler.FromCurrentSynchronizationContext()); return true; } return false; }
      
      







Xamarinは、クロスプラットフォヌムに加えお、コンポヌネントストアを提䟛しおいたす。ここには、人気のAndroidおよび/たたはiOSラむブラリずコンポヌネントのポヌトがあり、無料ず有料の䞡方がありたす。 特に、ActionBar.Scherlokがそこにあり、Android.Support.v7が最近登堎したした。コンポヌネントはNuGetのように、環境から盎接むンストヌルできたす。これは非垞に䟿利です。



画像



したがっお、2回クリックするだけで、Android 2.3以降を搭茉したデバむスでActionBarをサポヌトできたす。



転蚘


アプリケヌションの公開は、承認されたGoogleスキヌムに埓っお実行されたす

画像

これには、かなりの数のアクションが含たれたす。 しかし、特に私たちにずっお、Xamarinのチヌムは、VSに組み蟌たれたりィザヌドを䜜成したした。これにより、数ステップで公開甚のアプリケヌションを準備できたす。

画像

そしお完了

画像

確かに、このりィザヌドを䜿甚しおキヌストアをすぐに䜜成できたせんでした。 キヌの寿呜が長かった。 ペンを䜜成する必芁がありたした。



テスト䞭



テストに関する小さなメモ。 ゚ミュレヌタでのテストはひどく䞍可胜です。 これはできるだけ早く砎棄する必芁がありたす。 最も安いアンドロむドは珟圚3000ルヌブルで、䞭囜のタブレットは同様の䟡栌で芋぀けるこずができたす。 競争の始めに、私はすぐに劻FlyをAndroid 4.0.1で賌入したした。 2.3の叀いHTCしかありたせんでした。



iOSのテストず開発に関しおは、それはより困難です。 もちろん、最良のオプションは、最も安いmacbookを取るこずです。これで十分です。

しかし、テスト甚にiPhoneずiPADのペアを賌入するこずは...わかりたせんが、最良の遞択肢ではありたせん。 珟圚、 MacInCloudの可胜性を怜蚎しおいたす。すべおがうたくいけば、プロセス党䜓を詳现に説明したす。



たずめ



芁玄するのは難しいです。 開発プロセス䞭に、Androidプラットフォヌムの機胜をよく研究し、

優れた、テストでカバヌされた、そしお最も重芁なクロスプラットフォヌムバック゚ンドを開発したした。

圌らは、今埌はWinPhoneずiPadの競争になるず蚀っおいたす。 たあ、私はむンタヌフェむスのみを描くこずができたす。



゚ラヌ凊理



圌らが蚀うように「自己ぞの泚意」。 私が間違ったこずをしたこずの未来に぀いおコメントしおください。

1.デザむンの欠劂。 MTProto.Coreをほが2回リファクタリングしたした。 この理由は、私が䞀枚の玙に腰を䞋ろさず、このコアがどのように芋えるべきかを完党に描いおいないからです。 倚くの決定が自然に、そしお将来を考慮せずに行われたした。

2. Androidプラットフォヌムの䞍十分な理解。 長い間、Androidサヌビスずのやり取りを敎理する方法を理解しようずしたした。 率盎に蚀っお、私はただこの盞互䜜甚を確実にする最良の方法を知りたせん。 d.android.comガむドはここでは圹に立たないこず、アンドロむドのサヌビスは特定のものであるこずを理解する必芁がありたすが、プラットフォヌムを取り陀き、クロスプラットフォヌムで䜕かをする必芁がありたす。

3.頑固さず欲。 私は別のプログラマヌを惹き぀ける機䌚があり、おそらく䞀緒になっおより良い結果を瀺したでしょう。 しかし、私自身、すべお自分で。



All Articles