Ionic, SignalR ve TypeScript ile Mobile Uygulama Geliştirme Bölüm 1
Selamlar,
Bu makalede Ionic ile Mobile bir uygulama geliştirip, ilgili servislerden çektiğimiz takım ve maç scorelarını bir grid üzerinde ekrana basacağız. Ionic ile ilgili daha detaylı bilgiye buradan erişebilirsiniz. Daha sonra favori takımlarımızı belirleyip, bunları mobile cihaz üzerindeki storage’a kaydedip ana sayfayada listeleyeceğiz. Ayrıca favorilere eklenen bu takım bilgisini, SignalR Webscoket ve WebApi servisi kullanılarak, custom oluşturulan bir sosyal takip sayfasına pushlayacak ve real time olarak göstereceğiz. Bu makaleyi okuyan kişilerin, Angular4 ve TypeScript 2’yi bildiği kabul edilecektir. Angular 4 ile alakalı detaylı bilgiyi bu video serisinden erişebilirsiniz. Bu makale serisine ait detaylı videoyu, makalenin devamında izleyebilirsiniz. TypeScript ile alakalı yazıya buradan erişebilirsiniz.
Signalr ile ilgili detaylı bilgiye buradan erişebilirsiniz. Gelin önce Ionic ile Mobile uygulamamızı Native olarak hem Ios hem de Android için yazmaya başlıyalım.
Kurulması Gerekenler:
- Node.js : https://nodejs.org ilgili siteden kurulur.
- Inonic cordova, ilgili makinaya kurulur: $ npm install -g ionic cordova. Ionic hakkında data detaylı bilgiye, kendi sitesi olan buradan erişebilirsiniz.
- İlk projenin oluşturulması “ionic start NavigateIonic tabs –cordova” tabler template’i şeklinde olacak, yeni bir Mobile Ionic projesi oluşturulur. Eğer “Ionic start –list” yazılır ise, Ionic için oluşturulabilecek diğer proje templateleri aşağıdaki gibi görülebilir:
4. “cd NavigateIonic” ve “code .” komutları yazılarak yeni oluşturulan Ionic 3 Projesi Angular 4 ve TypeScript ile birlikte Visual Studio Code idesinde açılır. VS Code bu link’den indirilebilir.
5. “Ionic serve” yazılarak uygulama 8100 portundan ayağa kaldırılır. Bu makalede Mobile uygulama olarak IOS ortmı örnek alınmış ve çalışılacak similatorler Iphone üzerinden belirlenmiştir.
6. Ben bu projeyi IOS ortamı için hazırlayıp, makaleye bu şekilde devam edeceğim. Zira benzer adımlar, android ortamı için de geçerli ve çok daha kolaydır. Mobile uygulamanın IOS Ortamında çalışması için platform olarak IOS’un eklenmesi gerekmektedir. IOS platformu “ionic cordova platform add iOS” komutu ile projeye eklenir. İlgili komutun çalıştırılmasından sonra proje içerisinde aşağıdaki gibi platforms adında bir klasör ve içinde ios folder’ının oluştuğu görülmektedir.
7. IOS ortamı için aşağıdaki komutların çalıştırılması gerekmektedir.
- sudo npm install -g ios-sim
- sudo npm install -g ios-deploy
Not: Eğer “ios-sim” global ortamda kurulmuyor ise: İlgili porje folder’ına gidilerek=> cd platforms/ios/cordova altında ==> “npm install ios-sim” komutu çalıştırılır.
8. Uygulamayı bilgisayarınızda IOS ortamında bir simulatorde görmeniz için “ionic cordova emulate ios” komutunun yazılması gerekmektedir. Eğere herhangi bir cihaz belirtilmez ise aşağıdaki gibi bir ekran ile karşılaşılır.
ionic cordova emulate ios -lc –target=”iPhone-7-Plus, 10.3″ komutu ile istenen bir model simulator olarak seçilebilir.
“ios-sim showdevicetypes” : Komutu ile, IOS için hangi cihazların simulator olarak çağrılabileceği görülür. Örnek çıktı aşağıdaki gibidir.
Son olarak Uygulamayı Apple tarafında Developer account’u almadan, yani 99$ ödemeden gerçek bir Iphone cihazında çalıştırmak için, öncelikle “https://apps.ionic.io/apps/” adresinden üyelik alınıp cloud’da bir application aşağıdaki gibi oluşturulmalıdır. Aşağıdaki resimde çerçeve içine alınan kısım, uygulamanın oluşturulmasından sonra alınması gereken ID’disidir. Uygulamada “ionic.config.json” dosyası altına “app_id:” yanına ilgili projenin ID’si, aşağıdaki gibi yazılır.
ionic.config.json
1 2 3 4 5 |
{ "name": "NavigateIonic", "app_id": "237f8455", "type": "ionic-angular" } |
İlgili uygulama console’unda, cloud’a önce “ionic login” yazılıp yukarıda üye olunan email ve password girilir. Daha sonra “ionic upload” ile ilgili uygulama cloud’a atılır.
IOS’da App Store’dan Ionic View indirilir. Üye olunan Email ve Password girildikten sonra upload edilen App, Iphone cihazda aşağıdaki gibi görülüp çalıştırılabilir.
Performance:
- IOS ortamında performansın arttırılması için “wkwebview-engine” kesinlikle tavsiye edebileceğim bir eklentidir. Kurulum komutu=> “ionic cordova plugin add cordova-plugin-wkwebview-engine”
Daha detaylı bilgiye “https://www.npmjs.com/package/cordova-plugin-wkwebview-engine” buradan ulaşabilirsiniz.
config.xml: Aşağıdaki komutlar eklenir.
1 2 3 4 |
<feature name="CDVWKWebViewEngine"> <param name="ios-package" value="CDVWKWebViewEngine" /> </feature> <preference name="CordovaWebViewEngine" value="CDVWKWebViewEngine" /> |
2. Android ortamı için “crosswalk-engine” kurmanızı tavsiye ederim=> “cordova plugin add cordova-plugin-crosswalk-webview”
3. Son olarak Ionic projenizde fastclick.js‘i kullanmanızı şiddet ile tavsiye ederim.
Not: Projenin yazıldığı platform, Mac’de OSX ortamında hazırlanmıştır. Var olan bu projenin, windows bir ortamda da çalıştırılması istenir ise ==>”npm rebuild node-sass –force” komutu ile uygulamanın tekrardan derlenmesi gerekmektedir.
Ionic serve Options:
- Yayımlanan projenin 8100 default portunu ==> “ionic serve -p 1453” şeklinde farklı bir portdan yayımlanmasını sağlıyabilirsiniz.
- Default başlangıç platformunu da ==>”ionic serve -t ios” şekline belirliyebilirsiniz. Veya her iki maddeyi birleştirip “ionic serve -p 1453 -t ios” da diyebilirsiniz.
DB VE Data: Şimdik gelin Mobile uygulamamız için gerekli olan data işini çözelim:)
Özellikle mobile uygulamalarda populer, bulut (Cloud) tabanlı bir platform olan Firebase’i, google’ın da satın alması ile kesinlikle tavsiye ediyorum. Gelin takımlar için kullanılacak json dosyasını buradan indirip, Firebase’e upload edelim. Bu dosya (Pluralsight’da Steve Michelotti’ye ait Ionic eğitimden alınmıştır.)
- Firebase’e google account’u ile girilir. Add project tıklanır. Adı ve bölge seçilir.
- Yukarıdaki resimde görüldüğü gibi Database sekmesinden Import JSON ile ilgili json atılır. Artık datalar Firebase database’inde bulunmaktadır.
- Son olarak yüklenen Json datadan turnuvalar kısmına gelinip, yukarısındaki link kopyalanıp, sonuna da “json” eklenir ve ilgili link (“https://elite-schedule-app-1bbf9.firebaseio.com/tournaments.json”), Postman‘de “Get” işlemine tabi tutulur ise, aşağıdaki gibi bir sonuç ile karşılaşılır: Yani herhangi bir servis yazmadan, ilgili dataya json formatında erişilmiş olunur.
Böylece data sorunu, Firebase kullanılarak hızlıca çözülmüştür. Artık Mobile uygulamayı kodlamaya başlıyabiliriz. Bu makale serisinde esas amaç, Ionic konularını tek tek incelemek yerine, bir projeyi baştan sona gerçek hayatta işe yarayacak toolar ile örneğin search, refresh, virtual scroll gibi componentler ile kodlamak olacaktır.
Inonic Cordova ile yapılan bir mobile uygulamada, ilk açılış sayfası “src/app/app.html” sayfasıdır.
app.html:
- “<ion-menu>” Ana sayfada menuye tıklandığında açılan kısımdır.Tüm sayfayı kapsar.
- “<ion-header><ion-toolbar><ion-title>” Yukarıdaki resimde de görüldüğü gibi sayfanın “Menu” yazan başlık kısmıdır.
- “<ion-content>” sayfanın body kısmıdır.
- “<ion-list><ion-list-header>Navigate” Sonradan eklenecek Turnuva ve Ana sayfalara gidilecek menudür. (click) eventi ile çağrılan methodlar sayesinde, ilgili sayfalara yönlenme işlemi yapılır.
- “<ion-list><ion-list-header>Favorites” Burada ise, sonradan favorilere eklenecek takımlar listelenecektir. “*ngFor” ile tüm takımlar gezilmiş, “(click)” eventi ile “goToTeam(fav)” methodu çağrılarak sonradan eklenecek takım detay sayfasına gidilmiştir.
- “<button menuClose ion-item>” Sağ tarafa doğru uzanan ok şeklinde bir button olarak ekranda gözükmektedir. “ion-item“==> ion-list’e ait bir nesnedir. “*ngFor=”let fav of favoriteTeams“” ==> favoriteTeams[] dizisindeki tüm takımlar gezilerek ekrana basılır. “(click)=”goToTeam(fav)”” ==>ilgili takım tıklandığında, takım detay sayfasına yönlenilir.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
<ion-menu [content]="content"> <ion-header> <ion-toolbar> <ion-title>Menu</ion-title> </ion-toolbar> </ion-header> <ion-content> <ion-list> <ion-list-header>Navigate</ion-list-header> <button menuClose ion-item (click)="goHome()">Home</button> <button menuClose ion-item (click)="goTournaments()">Find a Tournament</button> </ion-list> <ion-list> <ion-list-header>Favorites</ion-list-header> <button menuClose ion-item *ngFor="let fav of favoriteTeams" (click)="goToTeam(fav)"> {{fav.team.name}} </button> </ion-list> </ion-content> </ion-menu> <!-- Disable swipe-to-go-back because it's poor UX to combine STGB with side menus --> <ion-nav [root]="rootPage" #content swipeBackEnabled="false"></ion-nav> |
app.component.ts:
- “favoriteTeams“: İlerde Team sayfasında favorilere ekle button’u konacaktır. Bu button’a tıklanan takımlar, favorilere eklenecektir. İşte bu favorilere eklenen takımlar, ilgili menu sayfasında tanımlanan “favoriteTeams” dizisine [ ] atanıp listelenecektir.
- “rootpage” : Ana sayfanın, hangi sayfa olacağının belirlendiği değişkendir. Bu uygulamada ana sayfa “MyTeamsPage”‘ sayfasıdir. İlgili sayfa bir sonraki makalede detaylıca incelenecektir.
- “userSettings, eliteApi” : Bunlar projede, ilerde bolca kullanılacak olan custom servislerdir.
- “loadingController“: Servisden data çekilirken ya da sayfalar arası geçişte gösterilen yükleniyor ibaresine ait tooludur.
- Önemli Not: Default olarak gelen “this.statusBar.styleDefault()” yerine “this.statusBar.hide()” yapılması ile, özellikle Iphone için en üstteki saat, şarj durumu ve gsm logosu gibi bilgilerinin göründüğü kısım kolaylıkla kaldırılabilir. Böylece ekran daha performanslı bir şeklide kullanılabilir. Ancak bu durumda uygulamanızın Apple Store’a çıkması için gerekli olan onay sürecinden geçmesi, nerde ise imkansızz:) bir hal alacaktır. Apple bu konuyu, nerde ise bir takıntı haline getirmiştir. Eğer illa ki isteniyor ise, onay için ekranın full screen olarak kullanılma nedeni, çok iyi bir şekilde açıklanması gerekmektedir.
- Event: “this.events.subscribe(“favorites:changed”,()=>this.refreshFavorites());” Bu kısım aynı Redis Pub/Sub’da olduğu gibi “favorites:changed” kanalının dinlediği bir subscribe’dır. İlerde yazılacak olan, yeni bir takımın favorilere eklenmesi durumunda, bu kanala pubscribe yapılacak ve ilgili “refreshFavorites()” methodu call edilerek menüdeki listenin yenilenmesi asenkron olarak sağlanacaktır.
- “refreshFavorites()“: İlerki makalelerde yazılacak “userSettings” servisi ile favorilere atılmış Json liste çekilip, “favoriteTeams” değişkenine atanır.
- “goToTeam()” method ile favorilerde olan bir takım tıklandığında: “eliteApi” servisinin, “getTournamentData()” methodu ile, ilgili takıma ait bilgiler çekilip, “this.nav.push(TeamHomePage, favorite.team))” methodu ile, ilk parametre gidilecek sayfa, ikinci parametre takıma ait çekilen data bilgisi olacak şekilde yönlendirilir. Böylece sayfada gösterilecek takım bilgisi, daha sayfaya gitmeden, çekilip parametre olarak gönderilmesi sağlanır.
- “goHome()” menuden seçildiğinde, gidilecek olan ana sayfa, yani MyTeams sayfasına yönlenilir.
- “goTournaments()” menuden seçildiğinde, gidilecek olan ilerde yazılacak turnuvalar sayfasına, yani TournamentsPage sayfasına gidilir.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
import { Component, ViewChild } from '@angular/core'; import { Nav, Platform, LoadingController, Events } from 'ionic-angular'; import { StatusBar } from '@ionic-native/status-bar'; import { SplashScreen } from '@ionic-native/splash-screen'; import { MyTeamsPage } from "../pages/my-teams/my-teams"; import { TournamentsPage } from "../pages/tournaments/tournaments"; import { UserSettings } from "../shared/user-settings.service"; import { EliteApi } from "../shared/elite-api.services"; import { TeamHomePage } from "../pages/pages"; @Component({ templateUrl: 'app.html', }) export class MyApp { @ViewChild(Nav) nav: Nav; favoriteTeams: any; rootPage: any = MyTeamsPage; pages: Array<{ title: string, component: any }>; constructor(public platform: Platform, public statusBar: StatusBar, public splashScreen: SplashScreen, private userSettings: UserSettings, private loadingController: LoadingController, private eliteApi: EliteApi, private events:Events ) { this.initializeApp(); // used for an example of ngFor and navigation } initializeApp() { this.platform.ready().then(() => { // Okay, so the platform is ready and our plugins are available. // Here you can do any higher level native things you might need. this.statusBar.styleDefault(); this.splashScreen.hide(); this.refreshFavorites(); this.events.subscribe("favorites:changed",()=>this.refreshFavorites()); }); } refreshFavorites() { this.favoriteTeams = this.userSettings.getAllFavorites(); } goToTeam(favorite) { let loader = this.loadingController.create({ content: 'Şimdi Geliyor...', dismissOnPageChange: true }); loader.present(); this.eliteApi.getTournamentData(favorite.tournamentId).subscribe(res => this.nav.push(TeamHomePage, favorite.team)) } goHome() { this.nav.push(MyTeamsPage); } goTournaments() { this.nav.push(TournamentsPage); } } |
app.module.ts: Aşağıdaki module’de, projede nerde ise kullanılacak tüm child module ve providerlar tanımlanmıştır. Angular 4’den de bildiğiniz gibi eklenen tüm yeni sayfalar, servisler ve modullerin, app.module.ts’de tanımlanması gerekmektedir.
- declarations : Başlangıç olarak tanımlanan class’ın adı yazılır.
- imports : Diğer projeye eklenmiş child moduleler burada tanımlanır.
- entryComponents : Projenin ilk ayağa kalkacağı sayfalar, burada tanımlanır.
- providers : Projede kullanılcak servisler burada tanımlanır.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
import { BrowserModule } from '@angular/platform-browser'; import { ErrorHandler, NgModule } from '@angular/core'; import { IonicApp, IonicErrorHandler, IonicModule } from 'ionic-angular'; import { MyApp } from './app.component'; import { StatusBar } from '@ionic-native/status-bar'; import { SplashScreen } from '@ionic-native/splash-screen'; import { MyTeamsPageModule } from "../pages/my-teams/my-teams.module"; import { TournamentsPageModule } from "../pages/tournaments/tournaments.module"; import { TeamsPageModule } from "../pages/teams/teams.module"; import { TeamDetailPageModule } from "../pages/team-detail/team-detail.module"; import { GamePageModule } from "../pages/game/game.module"; import { MyTeamsPage } from "../pages/my-teams/my-teams"; import { StandingsPageModule } from "../pages/standings/standings.module"; import { TeamHomePageModule } from "../pages/team-home/team-home.module"; import { EliteApi } from "../shared/elite-api.services"; import { HttpModule } from "@angular/http"; import { UserSettings } from "../shared/user-settings.service"; import { IonicStorageModule } from '@ionic/storage'; import { MapPageModule } from "../pages/map/map.module"; import { VibrationPageModule } from "../pages/vibration/vibration.module"; import { GeoLocationPageModule } from "../pages/geo-location/geo-location.module"; import { CameraPageModule } from "../pages/camera/camera.module"; import { BarcodePageModule } from "../pages/barcode/barcode.module"; import { DvcmotionPageModule } from "../pages/dvcmotion/dvcmotion.module"; import { NotificationPageModule } from "../pages/notification/notification.module"; import { SQLite, SQLiteObject } from '@ionic-native/sqlite'; @NgModule({ declarations: [ MyApp ], imports: [ BrowserModule, IonicModule.forRoot(MyApp), IonicStorageModule.forRoot(), MyTeamsPageModule, TournamentsPageModule, TeamsPageModule, TeamDetailPageModule, GamePageModule, StandingsPageModule, TeamHomePageModule, HttpModule, MapPageModule, VibrationPageModule, GeoLocationPageModule, CameraPageModule, BarcodePageModule, DvcmotionPageModule, NotificationPageModule ], bootstrap: [IonicApp], entryComponents: [ MyApp, MyTeamsPage ], providers: [ StatusBar, SplashScreen, EliteApi, UserSettings, SQLite, { provide: ErrorHandler, useClass: IonicErrorHandler } ] }) export class AppModule { } |
Geldik bu ilk Ionic-Cordova Angular 4 Mobile application makalesinin sonuna. Bu bölümde gerekli çalışma ortamının hazırlanması yani Nodejs, Ionic Cordova ve Ios için gerekli similatörlerin kurulması gibi temel bileşenler gösterilmiştir. Datanın çekileceği kaynak olarak Firebase kullanılmış ve Dummy bir Json data, çalışma amacı ile Cloud’a atılmıştır. Ayrıca başlangıç sayfası olan “app.html” ile konuya bir giriş yapılmıştır. Projede tanımlanması gereken app.module.ts sayfası detaylıca anlatılmıştır. Performans için platformlara özel neler yapılabileceğinden bahsedilmiştir.
Bir sonraki makalede yeni bir sayfa generate etme yolları, çok önemli olan Ionic Page LifeCycle, Loading Controller, Pull Request, Local Storage ve zaman kalır ise Ionic’de Pub/Sub anlatılacaktır.
Bir sonraki makalede görüşmek üzere hoşçakalın.
Kaynaklar: Pluralsight Steve Michelotti, https://ionicframework.com, https://github.com/ionic-team/ionic, Gaurav Saini’nin “Hybrid Mobile Development with Ionic” kitabından faydalandım.
Emeğine sağlık güzel paylaşım.
Teşekkürler,
Makale serisine bir giriş işte.
Merhaba Bora Bey,
Yazı ve paylaşım için çok teşekkür ederiz. İhtiyaçlar ortaya çıktığında ihtiyaca uygun en uygun çözüm neyse onu kullanmak gerektiğine biz de inanmaktayız ancak Xamarin yerine ionic neden kullandınız? Fiyat politikasından dolayı mı?
Selamlar,
Makalenin başındaki video bu soruya cevap teşkil etmektedir. Bir seçim yoktur. Hepsi ile yazıyorum. Hepsinin kendine göre üstünlükleri var.
Son olarak Xamarin’de artık ücretsizdir.
İyi çalışmalar.
Çok teşekkürler Bora Bey, emeğinizin karşılığını ödeyemeyiz.
Ben teşekkür ederim :)
Emeğinize sağlık hocam. Kapsamlı bir okadar da yorucu bir makale olmuş.
Teşekkürler. Bu makalelerden daha çok var :)
ionic upload komutunda aşağıdaki sorun yaşanıyor. Bunu nasıl aşabiliriz ?
Sorry! The configured backend (pro) does not know about ionic upload.
Selamlar,
Hatadan da anlaşıldığı gibi, Upload için kullanılan component eklenmemiş.