github pages

Uzun bir aradan sonra github pages ile yeni yazılar yayınlayamadığımdan dolayı jekyll-now forklayarak blogumu tekrar oluşturdum. Umarım tekrar yeni yazılarda görüşürüz…

Read More

Android Manifest Merging & Overriding

Android projelerinde kullandığımız third party bileşenlerin de kendine özgü çalışma zamanı izinleri (runtime permissions) olabiliyor. Bu izinler genellikle önceden readme dosyalarında "şu izinleri de eklemelisiniz" şeklinde yer almaktayken son zamanlarda kullandığım bir bileşenin üst versiyonunu kullandığımda uygulamanın otomatik olarak bazı ek izinlere daha ihtiyaç duyduğunu gördüm.
Ayrıca bileşen aar şeklinde paketlenmiş halde geldiği için hemen manifest dosyasına bakma imkanım da olmadı. Kısa bir araştırma ile manifest merging işleminin -önceden de minSDK versiyonu için aynı durumu birkaç kez yaşamıştım.- tüm bağımlılıkları da kapsayacak şekilde yapıldığı ve istersek aşağıdaki gibi uygulamamızın manifest dosyasına ekleyeceğimiz remove node attributeu ile bu izinden kurtulabileceğimizi buldum. <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" tools:node="remove"> </uses-permission> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" tools:node="remove"> </uses-permission>
Read More

Android Studio Incremental Build, Gradle 2.1

Gradle 2.1 ile gelen yeni bir özellik olarak incremental build gerçekten önemli bir kilometre taşı olabilir. Projenin gradle versiyonu 2.1 e çıkarıldığında otomatik olarak incremental build özelliği aktive olmuyor. Aşağıdaki kod parçasını tüm modüllerin en tepesindeki build.gradle dosyasına eklemek gerekiyor:
allprojects { tasks.withType(JavaCompile) { options.incremental = true } }
Gradle sync yaptıktan sonra Android studioda Run butonunda incremental build için gelen küçük simgeyi görebileceksiniz.
Bir başka yazıda görüşmek üzere.
Read More

Postgresql Sequence Tanımlayarak AutoIncrement alanlar oluşturmak

Postgresql ile otomatik artan alanlar oluşturmak için serial veritipi kullanılacağı gibi klasik yöntem olarak sequence tanımlanır. create sequence seq_news_source_url start 120; gibi bir tanımla 120den başlayarak artacak bir sequence eklemiş olduk.
Insert statementlarınızda bu alan için zaten autoincrement diye bir değer belirtmemişseniz veya Mysql migration sonucunda buraya gelmişseniz tablodaki bu alan için default deger set edebilirsiniz. alter column user_id smallint NOT NULL DEFAULT nextval('seq_news_source_url')
Read More

Overriding Vs Shadowing

Java ile kod yazarken çok can yakacak bir konuya değinmek istiyorum: Overriding & shadowing. Çok biçimlilik(polyformisim) ve Kalıtımda(-inheritance- sınıflar arası miras) genel konsept değişkenlerin maskelenmesi, metodların ise override edilmesidir. Bu kavram "variables are shadowed and methods are overridden" olarak literatürde de yer almıştır. Yani bir sınıfı extend ettiğimizde sınıfta varolan aynı isimdeki değişkenlerin her alt sınıfla üstü örtülürken(aslında hala yaşamakta ve erişilebilir olmaktadırlar) metodlar için tam bir üstüne yazma işlemi gerçekleşir. ([1]Yine metod signature için bu override işlemi de yeterli değildir ve ilkel sınıf referansı ile gelişmiş nesne metodlarına erişirken temel sınıf metodunun fırlattığı checked exceptionları ele almak gerekir.)

Static değişkenler ve metodlar içinse durum daha farklıdır. Static olarak belirtilmiş değişkenler yine maskelenmiş olarak tutulurken (shadowed) bu kez metodlar da override edilemez ve shadowed olarak her sınıfta farklı metodmuş gibi davranırlar. Zaten @Override annotasyonu da bu durumlar içindir. Zorunlu bir annotation olmasa da geliştiricinin kendi ayağına sıkmaması için override ettiğini sandığı her metodun üstünde belirtmesi bu tip durumlarda "... must override or implement a supertype method" ve "1 quick fix available: remove @Override annotation" şeklinde IDE compileri tarafından verilen uyarıdan anlaşılacaktır.

Buraya kadar overrided ya da shadowed bir şekilde istediğimiz gibi alt sınıflarda da aynı isimde ve aynı metod imzasında değişken ve metodlar tanımlamış olabiliriz ve bu metodları da kullanırken herhangi bir yan etki ile karşılaşmamış olabiliriz. Bunun da sebebi nesne referanslarımızın sıkı sıkıya bağlı olmasından kaynaklıdır.

Aşağıdaki örnek kod dosyasında maskelenmiş bir değişkene nasıl erişildiği görülebilir. SpecialEmployee ve RegularEmployee tipinden referanslarla erişilen SpecialEmployee nesnesinde req referansı compile time için RegularEmployee sınıfının metodu olarak görünse de overriding mekanizması çalışmakta ve yine gerçek nesnenin metodunun işlevi yerine getirilmektedir. Ama poliformizim değişkenler için aynı şekilde çalışmamaktadır ve konsept devreye girer, shadowed değişken ortaya çıkarak temel sınıfa ait değişken değeri ekrana bastırılır.

Çıktı:
Multiplier: 0.03 variable a: 11
Multiplier: 0.03 variable a : 9

import java.math.BigDecimal;

class RegularEmployee {
int a = 9;
    private BigDecimal salary;

    public void setSalary(BigDecimal salary) {
        this.salary = salary;
    }

    public  BigDecimal getBonusMultiplier() {
        return new BigDecimal(".02");
    }

}

public class SpecialEmployee extends RegularEmployee {
int a = 11;
    @Override
public  BigDecimal getBonusMultiplier() {
        return new BigDecimal(".03");
    }
    
    public static void main(String args[])
    {
    SpecialEmployee spe = new SpecialEmployee();
    RegularEmployee req = new SpecialEmployee();
    System.out.println("Multiplier: " + spe.getBonusMultiplier() +" variable a: " + spe.a);
    System.out.println("Multiplier: "+req.getBonusMultiplier() +" variable a : " + req.a);
    
    }

}

Read More

Her Java Uygulama Geliştiricisine Lazım Kütüphaneler-1 Minimal JSON

Kimi zaman Android-Arsenal ya da farklı blog yazılarını takip ederken sıklıkla kullandığımız bazı açık kaynak java kütüphanelerinin daha iyi alternatifleriyle değiştirilebileceğini görüyorum. Burada da bu kütüphaneleri paylaşacağım. Eclipse RAP projesinde json ile çok fazla işlem olması ve yeterli performans değerlerini org.json kütüphanesi ile yakalayamadıkları için ortaya çıkan minimal json ile hem performans yönünden varolanlar arasında  eşsiz, hem de sadece okuyacağınız ve belki de çoğu zaman rest bir kaynaktan gelen ve sürekli değişken tipteki verileri de içerebilecek json içerikleri için pojo üretmeye gerek duymayan kodlar yazmak mümkün.

https://github.com/ralfstx/minimal-json

JsonObject jsonObject = JsonObject.readFrom( reader );
JsonArray jsonArray = JsonArray.readFrom( string );
String name = jsonObject.get( "name" ).asString();
int age = jsonObject.get( "age" ).asInt(); // asLong(), asDouble(), ...
String name = jsonArray.get( 0 ).asString();
int age = jsonArray.get( 1 ).asInt(); // asLong(), asDouble(), ...
Read More

Android ADB Path Ayarı (MacOs)

Linux shell scripting ve konsola çok uzak olmasam da windows/linux farklılıklarından dolayı bir türlü path değerini doğru export edemem. Buraya yazarak bundan sonraki kurulumlarda daha hızlı bir erişimi hedefliyorum:)

nano .bash_profile
komutu ile dosyasını açıyoruz.

export PATH=$PATH:/Users/onuratci/Documents/DeveloperTools/android-sdk-macosx/platform-tools/

yazarak  .bash_profile dosyamızı kaydediyoruz.
Terminali kapatıp yeniden açtığınızda  adb komutu hazır olacaktır.
Read More

Switch Case Farklı Kullanımları

char c = 'c';

switch (c) {
case 'a':
System.out.println("a");
default:
System.out.println("default");
case 'c':
System.out.println("c");
}

int i = 4;

switch (i) {
default:
System.out.println("default");
case 5:
System.out.println(5);
case 3:
System.out.println(3);
}
 
gibi bir kullanımda default case için ortada ya da en üstte bir kullanım mümkün olduğu gibi davranış olarak da ilk switch statementinde ekran çıktısı:
"c"
olurken ikinci statement için ekran çıktısı:
"default
5
3"
olacaktır.  Ayrıca case ve default labellarının break ile bitmemesinden dolayı ilk eşleşen label sonrası tüm caselerin çalıştırıldığı da dikkat edilmesi gereken bir konu.
Read More

Android Studio: A Valid JVM Was Not Found on This Machine Hatası

Android Studio IntelliJ alt yapısını kullanan ve son zamanlarda gradle build konfigurasyonu ile gelecek vaad eden bir yapı sunmasıyla benim de sonunda yavaştan migrate etmek zorunda kaldığım bir platform haline geldi. Android Studio kurulumu kolay olsa da  başlıktaki hatayı alırsanız:

launchctl setenv STUDIO_JDK /Library/Java/JavaVirtualMachines/jdk1.8.0_25.jdk

komutu ile Android Studio ile bilgisayarınızda kurulu JDK yolunu bir defaya mahsus ayarlamak yeterli.
Read More

ADB Komutları

Android SDK içinde gelen bazı yardımcı araçlarla bazı işlemleri kısa yoldan yapmak mümkün. Çok kullanılan komutlar oldukları için ilerde aramamak için not almak istediğim birkaç komut:

-Bootloader moduna geçmek:
./adb reboot bootloader

-Bootloader dosyasını yüklemek:

./fastboot flash bootloader ~/Downloads/bootloader-hammerhead-hhz12d.img

-Radio dosyasını yüklemek:

./fastboot flash radio  ~/Downloads/radio-hammerhead-m8974a-2.0.50.2.22.img

-Bootloader unlock işlemi için:

1. Önce yukarıda verilen komutla boot loader moduna geçilir.
2. "fastboot oem unlock" komutu ile cihaza unlock komutu verilir ve ekrandan onay sağlanır.

Read More

Patch Oluşturma

Linux uygulamalarının kaynak kodunu düzenleme ve yeni eklemelerde bulunma gereksinimi oluştuğunda kaynak koda yama oluşturularak her platformda bu oluşturulan patch dosyası ile derleme yapılması daha uygun olacaktır. Patch oluşturmanın çok farklı yöntemleri ve araçları olsa da en basiti terminaldeki diff uygulamasını kullanmak diyebilirim.

diff -Naur varolan_kod_dosyasi degisiklik_yapilan_kod_dosyasi > patch.txt
komutu ile patch.txt içerisine kodda yapılan ekleme ve çıkarma işlemlerinin bir özeti çıkarılmış olur. Zamanım olursa bir sonraki yazımda linux source rpmlerinin patching işlemininden de kısaca bahsetmek istiyorum.
Read More

MacOSX Fusion Drive Özelliğini Kapatma

MacosX Mountain Lion ile ön plana çıkarılan Fusion Drive özelliği ile  sistemdeki SSD ve Hard diskleri sanal bir disk grubu altına toplayıp sık kullanılan ya da sistem ögelerinin SSD üstünden sunulması sağlanıyor. Böylece hem birleşik bir kapasite hem de yüksek hız sağlanıyor. Mac bilgisayarınızda birden fazla disk varken eğer Mountain Lion ya da Mountain Lion tabanlı bir recovery yüklemesiyle DiskUtil programını çalıştırdığınızda bu disklerin Fusion Drive ile kullanılmamasını düzeltilecek bir durum olarak algılayıp onay istiyor. Yanlışlıkla da olsa onay verirseniz diskiniz SSD ile hibrit bir disk olarak bir volume grup altında birleşiyor.Bu volume grup aslında Linux sistemlerden alışkan olduğumuz ve tahminen çalışma mantığının da çok benzer olduğu LVM yapısı. Bu grubu silmek ve fusion drive özelliğini kapatmak için Recovery ekranında Terminali açıp,

diskutil coreStorage list
komutu ile kök volume grup IDsini görüntüleyebilirsiniz. 798342-3242342-234234-234234 gibi bir volume grup ID görüntülenecektir.
Daha sonra bu ID değerini kopyalayıp Terminale,

diskutil coreStorage delete 798342-3242342-234234-234234 
komutunu verdiğimizde ID ile geçtiğimiz sanal disk grubunu silmiş ve disklerimizi eski haline getirmiş oluyoruz.

Read More

Android Video Kaydetme

Android cihazdan geliştirme yaparken ekranda yapılan işlemleri video olarak dışarı aktarmak istiyorsanız emülatörde işlemleri yapıp bilgisayardan video kaydetmek dışında daha güzel bir yol bulunuyor. Android 4.4+ cihazların 3 dakikaya kadarki ekran değişiklikleri video olarak export edilebiliyor. Bu işlem için cihaz usb debugging aktif olarak bilgisayarınıza bağlı olmalı ve adb kullanarak aşağıdaki komutu çalıştırıp 3 dakika kadar video çektikten sonra istediğiniz bir zamanda bilgisayardan CTRL+C ile kesme yollamalısınız.
SD kart konumu değişebilir. Nexus 5 için

./adb shell screenrecord /mnt/shell/emulated/0/3.mp4
./adb pull /mnt/shell/emulated/0/3.mp4
Read More

Spring MVC PathVariable İle Nokta İçeren Değerlerin Taşınması

Spring RequestMapping tanımlarken
/somepath/{variable}
gibi bir tanımlama yapıldığında
/somepath/var1.var2
gibi bir istek sonucunda controller metodumuza gelen variable değeri "var1" olarak nokta karakterinden sonrası atılmış olarak gelecektir. Bu durumu ortadan kaldırmak için
/somepath/{variable}/
gibi sonlandırıcı / karakterini de ekleyip kullanmak gereklidir. Ama bazı durumlarda sonraki / karakterinin eklenmemesinin gerektiği ya da eklenemediği durumlar oluşabiliyor. Bu durumda da RequestMapping tanımında value değerine geçilmesi gereken parametre
/somepath/{variable:.+}
şeklinde set edilmesi gerekir. Burada bu path için gelecek page.jsp gibi değerlerde de jsp kısmının aktarılacağı ya da /somepath/var1.var2.var3 gibi bir istek sonucu variable değerinin "var1.var2.var3" olarak geleceği unutulmamalıdır.
Read More

SQL Group Concat

Birden fazla satırı bir sorguda ya da alt sorguda tek alanda birleştirmek gerektiğinde sadece MySQL ile kullanılabilecek bir fonksiyon bulunmakta. group_concat fonksiyonu ile birleştirilmek istenen alan adı ve ayıraç girilerek aşağıdaki gibi bir sorguda tekli sonuç alınabilir. Özellikle subquery olarak bilgi amaçlı listelenecek alanların birleştirilmesi ve çoklu satır alınmasından kaçınılabilir.

MesajID      Alici
---------      -----
5                 Onur
6                 Ugur
7                 Ahmet

select group_concat(Alici,',') where MesajID > 0
sorgusu çalıştığında
Onur,Ugur,Ahmet
sorgu cevabı oluşacaktır.
 
Read More

Uzak Sunucudaki Mysql Servisine SSH ile Güvenli Bağlantı

Sunucudaki mysql ya da farklı bir servise firewall üzerinden izin vermeden bağlanabilmek gerekebilir. Bu genellikle production ortamına bağlanılması gerektiğinde sadece ssh bağlantısı ile bağlanmanın güvenli olduğu durumlarda ortaya çıkar. Yerel bilgisayardan sürekli bir ssh bağlantısı açılarak sunucunun 3306 portu yerel bilgisayarın 3306 ya da farklı bir portuna bağlanabilir. Aşağıdaki ilk komut ile localde de 3306 portu ile çalışılmak istendiği varsayılmıştır. İkinci komut ise bilgisayarınızda zaten mysql kuruluysa farklı bir porttaymış gibi uzak sunucunun mysql sunucusuna bağlantı açmaya yarar.

ssh -L 127.0.0.1:3306:127.0.0.1:3306 user@example.com -N 
ssh -L 127.0.0.1:3307:127.0.0.1:3306 user@example.com -N 
user@example.com kısmının root@sunucuIP olarak değiştirilmesi yeterlidir.
Read More

Apache Tomcat PermGen Space Hatası ve Memory Ayarları

Tomcat varsayılan bellek limitleri bir süre sonra bellekte ve java byte kod işletiminde hataya yol açacaktır. Bu sebeple tomcat kurulumundan sonra projenin ve sunucu bellek miktarının göz önünde tutularak aşağıdaki satırın tomcatdir/bin/setenv.sh adında bir dosya içeriğinde bulunması gerekmekte.

export JAVA_OPTS="-Dfile.encoding=UTF-8 -Xms128m -Xmx1024m -XX:PermSize=64m -XX:MaxPermSize=256m"

Windows sunucuda(!) tomcat çalıştırma durumuna düşerseniz platform olarak birbirlerini hiç sevmeseler de  (ya da sevmesem de)

tomcatdir/bin/setenv.bat

dosyasını oluşturup

set JAVA_OPTS=-Dfile.encoding=UTF-8 -Xms128m -Xmx1024m -XX:PermSize=64m -XX:MaxPermSize=256m

olarak parametreleri yazmak yeterli.

Ek Bilgi ve Güncelleme:
Class meta data depolama ve permanent generation konusunda JDK 8 ile değişiklik yapılarak native memory alanına taşındığı için permGen parametresinin set edilmesine JDK8 üzerinde çalışan sunucularda gerek kalmıyor. Ayrıca bu parametrenin gözönüne alınmadığına dair bir mesaj da sunucuda başlangıçta loglara düşüyor.
http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6964458
This project will remove the permanent generation from the hotspot heap.  Doing
so removes the need for tuning the size of the permanent generation and also
allows an implementation that is more amenable to the concurrent collection of
the meta data. This project will move the contents of the permanent generation
either to the Java heap or to native memory.
Read More

Centos/Redhat İşletim Sistemi Limitlerinin Yükseltilmesi

İşletim sisteminde Oracle Veritabanı ya da Java Application Server gibi işletim sistemi açısından üst seviye fakat yoğun sistem kaynağı kullanabilecek uygulamaları kullanırken bir süre sonra yük arttığında açık dosya işaretçisi kalmadığı için hata oluşması gibi işletim sistemi seviyesinde kısıtlar ortaya çıkabilir. Bu limitleri yükseltmek ve bazı değerleri optimum seviyeye çekmek için aşağıdaki parametreleri ilgili dosyalara ekleyebiliriz.

/etc/security/limits.conf dosyasında dosya sonuna eklenecek parametreler:

* hard nofile 781610
* soft nofile 781610
* soft nproc 781610
* hard nproc 781610

/etc/sysctl.conf dosyası sonuna eklenecek parametreler:

# increase TCP max buffer size setable using setsockopt()
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.core.netdev_max_backlog = 2500
# increase Linux autotuning TCP buffer limits
# min, default, and max number of bytes to use
net.ipv4.tcp_rmem = 8192 87380 16777216
net.ipv4.tcp_wmem = 8192 65536 16777216
# don't cache ssthresh from previous connection
net.ipv4.tcp_no_metrics_save = 1
net.ipv4.tcp_moderate_rcvbuf = 1
fs.file-max = 781610


Read More

Centos/Fedora/Redhat Sistem Zaman Dilimi Değiştirme

Varsayılan olarak UTC kullanan sistem saatini yerel bir zaman dilimine göre set etmek için /etc/localtime dosyasını silip /usr/share/zoneinfo altındaki dosyalardan uygun olanını sembolik link olarak /etc/localtime dosyasına bağlamak yeterlidir.

rm -rf /etc/localtime
ln -s /usr/share/zoneinfo/Europe/Istanbul   /etc/localtime


Read More

Cordova 3.1 Güncellemesini Varolan Uygulamalara Uygulamak

Cordova 3.1 (phonegap) güncellemesini almak için sistemimizde

$ sudo npm update -g cordova


komutu ile kolayca güncellenebilir. Fakat varolan uygulamalar için de CLI üzerinden güncellemeleri uygulamak gerekmekte. Öncelikle proje dizinine ilerledikten sonra proje klasöründe

$ cordova platform update ios


komutu ile platform bazında gerekli güncellemeler de uygulanacaktır. Güncelleme işlemi öncesinde kod versiyonlama sistemi kullanılmıyorsa projeyi yedeklemeniz önerilir. Projede android platformu ekliyse ios yerine android yazılmalıdır.

Cordova 3.1 Changelog
Read More

Time Backup Stili RSync Backup

MacOs ile kullanabildiğimiz Time Backup yazılımının sağladığı incremental backup özelliğini rsync ile tüm platformlarda uygulayabilmek için github üzerinde bir proje başlatılmış. 
Kullanımı gayet kolay ve yedekler alınırken eski yedeklere hard-link ile bağlanıyor. Böylece yedekler çok az yer kaplamış oluyor. Scriptin kurulumu ve kullanımı da çok kolay. 
Ayrıntılı bilgi için: github rsync time backup
Read More

Komut satırından eposta kontrolü

Bazen komut satırından mailleri kontrol etmek gerekebilir. Böyle birşey nasıl yapılır derken internette varolan bilgilerle şu şekilde bir script derledim. MacOs, Linux ya da Windows ile Cygwin üzerinde çalışabilir bir script, curl ve perl gerektirir.
Not: Kodları inceleyince anlaşılacağı gibi gmail ve gmail tabanlı posta servisleri için geçerli bir scripttir.


curl -u user@gmail.com:password --silent "https://mail.google.com/mail/feed/atom" | perl -ne 'print "\t" if //; print "$2\n" if /<(title|name)>(.*)<\/\1>/;'
Read More

Dosya Sistemindeki Büyük Boyutlu Dosya ve Dizinleri Bulma

Bazen sunucuda dolan diskin hangi klasörde varolan verilerden kaynaklandığını bulmak için kullanılabilecek bir script:
(Scriptteki / kök dizinden itibaren sıralama yapılacağını belirtmektedir. Sadece belirli bir klasörde aramak için /var gibi bir alt dizin verilebilir. 20 parametresi gösterilecek adedi belirler.)

#du -a / | sort -n -r | head -n 20



Çıktısı:

1576888 /var
1533160 /var/lib
1487384 /var/lib/mysql
534532  /var/lib/mysql/ibdata1
518304  /var/lib/mysql/keptest02.err
254000  /var/lib/mysql/mysql-bin.000006
63376   /var/lib/mysql/mysql-bin.000017
61240   /var/lib/mysql/mysql-bin.000015
38292   /var/cache
37616   /var/lib/rpm
37392   /var/cache/yum
37388   /var/cache/yum/i386
37384   /var/cache/yum/i386/6
33476   /var/lib/mysql/mysql-bin.000016
30092   /var/lib/rpm/Packages
19896   /var/cache/yum/i386/6/updates
Read More

Cordova IOS7 Status Bar UI İçin Bir Düzeltme

Cordova ile uygulamalarda ios 7 sonrasında oluşan status barın uygulama arayüzünü override etmesi sorunu ile ilgili olarak bulduğum en iyi çözüm şu şekilde:

-MainViewController.m dosyasında ViewDidLoad metodunda [super viewDidLoad]; satırı sonrasına eklenebilir:


NSArray *vComp = [[UIDevice currentDevice].systemVersion componentsSeparatedByString:@"."];
if ([[vComp objectAtIndex:0] intValue] >= 7) {
// iOS 7 or above
CGRect oldBounds = [self.view bounds];
CGRect newViewBounds = CGRectMake( 0, -10, oldBounds.size.width, oldBounds.size.height-20 );
CGRect newWebViewBounds = CGRectMake( 0, -20, oldBounds.size.width, oldBounds.size.height-40 );

[self.view setBounds:newViewBounds];
[self.webView setBounds:newWebViewBounds];
}



Ek bilgi: Status bar görüntülenmesin isteniyorsa şu şekilde bir çözüm ile tamamen full screen bir uygulama tasarımına gidilebilir.
http://stackoverflow.com/a/20152984

Read More

iOS Uygulamasının App Store' da Yayınlanması


Emulatörde test edilen uygulamanın yayınlanması için AppId oluşturulması, provizyon sertifikasının geliştirme ve yayınlama için üretilmesi gibi bir dizi işlemin tamamlanması gerekir. Bu yazıda kısaca bu işlemlerin hangi sırayla yapılması gerektiği ve bazı ipuclarını paylaşacağım.

Önemli Not: App Store Distribution Guide daha detaylı ve güncel bilgiler içermektedir. Geliştiricilerin öncelikle bu dokumana göz attıktan sonra aşağıdaki bilgileri ancak ip ucu ve hatırlama amaçlı olarak kullanabileceğini düşünüyorum.
  1. Cihazın XCode tarafından geliştirme amaçlı kullanılabildiğinden emin olunmalıdır. Cihazı usb kablo ile bağladıktan sonra XCode->Window->Organizer penceresinde Devices sekmesi altında takılı olan iphone/ipad cihazı görüyor olmamız gerekir. Burada cihazın adına sağ tıklayarak "Add Device to Provisioning Portal" e tıklayarak cihazı geliştirme amaçlı olarak kullanabilmeyi aktive edebiliriz.
  2. App ID oluşturulması: iOS Developer hesabımızı kullanarak member center a giriş yapıyoruz. Buradan Certificates,Identifiers Profiles kısmına tıklayarak Identifiers alanındaki App IDs kısmına geçiyoruz. Burada daha önceden oluşturulan wilcard (*)  idleri listelenecektir. Bir uygulamaya benzersiz Id değeri vermeden de uygulamanın yayınlanması mümkündür. Fakat burada uygulamaya daha sonradan eklenecek push notification, iAd entegration gibi işlemlerde bir daha geri döndürülemeyecek şekilde bu özellikleri kullanamama durumu ortaya çıkacaktır. Her uygulama için bir App ID oluşturmak uygulamanın geleceği açısından büyük önem taşır.
  3.  App IDs kısmında sağ üst köşede bulunan + butonuna tıklayarak yeni App Id oluşturabiliriz. App Name kısmına uygulamamızın adını, Explicit App ID kısmına da com.onuratci.ios.appname şeklinde paket adını yazabiliriz. Burada apple developer hesabımızla ilişkili identifier kullanılacağı için sonuçta Y6GHZA5.com.onuratci.ios.appname şeklinde benzersiz bir ID değeri ortaya çıkacaktır. 
  4. App Id oluşturma işlemi tamamlandıktan sonra tekrar XCode uygulamasına dönerek Window->Organizer ekranından refresh butonu ile provizyon profillerinin sunucudan yenilenmesini isteyebiliriz. bu sayede eklediğimiz app id için yeni provizyon sertifikaları tanımlayabilir hale geleceğiz. 
  5. Development Profilinin Oluşturulması: Organizer penceresinde en üstte bulunan provisioning profiles altında New seçeneği ile yine geliştirici hesabımıza giriş yaptığımızda App ID kısmına az önce eklediğimiz uygulamanın da geldiğini görürüz. Buradan uygulamamıza provision profile adı, emulasyon için gerçek cihazı IDsi  ve uygulama ID değerini seçerek yeni profil tanımlamayı tamamlarız.
  6. Distribution Profilinin Oluşturulması: Profili tanımladıktan sonra distribution profile oluşturmak için tekrar member center alanındaki profiles kısmından distribution profiles kısmına yeni seçeneğini seçerek bu defa app distribution için profile oluşturma işlemini tekrarlayabiliriz. Bu sihirbazda seçtiğimiz App ID için dağıtım profili oluşturulacak ve indirilebilir halde bize sunulacaktır. İndirdiğimiz profil dosyasına çift tıklayarak doğrudan XCode üzerindeki Organizer alanına eklenmesini sağlayabiliriz.
  7. Code Signing (Development/Distribution): Kod imzalama development için eklediğiniz cihazınıza uygun profil ile ya da app store'da yer alacak şekilde distribution profili ile imzalanması anlamına gelmektedir. XCode üzerinde Projects penceresinde proje seçildiğinde Build Settings -> Code Signing  kısmında Code Signing Identity özelliğinin birden çok değer içerdiği görülecektir. Burada az önce oluşturulan uygulamaya özel (wildcard * profiller de listelenir) Uygulama Adı- Development / Distribution şeklinde iki profilin de bulunuyor olması gereklidir. Burada uygulamayı build ederken test cihazımıza göndereceksek developer profili ile uygulama app store'da yayınlanacak şekilde build edilirken de distribution profili ile imzalandığından emin olmalıyız. 
  8. Uygulamanın App Store'a aktarılması: Bu aşamada yine XCode tarafından bir dizi işlem sonucu code signing alanında distribution profili ile projenin Product menüsünden clean,build ve archive işlemlerini takip edecek şekilde app store için binary oluşturulması işlemini tamamlayabiliriz. Burada önemli bir koşul olarak archive aşamasında xcode ile çalıştığımız bilgisayarda ipad/iphone cihazının takılı olması ve run configuration kısmında bu cihazda çalışacak şekilde seçili olması gerekmekte. Organizer penceresinde önce oluşturduğumuz arşiv dosyasını validate seçeneği ile bir dizi doğrulama işleminden geçiriyoruz. Burada herhangi bir sorun olduğunda hata mesajı ile birlikte app store 'a yükleme işlemini iptal edecektir. Belirtilen sorunu çözdükten sonra tekrar bu aşamaları takip ederek validate işleminden geçtikten sonra ise distribute seçeneğine tıklamak ve uygulamanın app store'a yüklenmesini beklemek gerekiyor. Bu aşamada diğer önemli bir konu ise validate aşaması öncesinde itunesconnect üzerinden uygulamanın app store kaydının oluşturulması, gerekli tüm ücretlendirme ekran görüntüsü, açıklama ve uygulamaya özel şifreleme algoritması kullanılıp kullanılmadığının seçilmesi gerekiyor. Uygulama itunesconnect üzerinde "ready to upload" durumuna geldiğinde XCode üzerinde validation ve distribution işlemleri yapılabilir.

    iOS7 için önemli not: Bir hafta öncesine kadar yapılan gönderimlerde bir sorunla karşılaşılmasa da XCode ile validation işleminden geçen ve review işlemine gönderilmiş uygulamanız için app storea yükleme anından birkaç dakika sonra icon dosyalarının eksik olduğu ile ilgili uyarı gelebilir. Burada sorun iOS 7 ile gelen yeni icon standardına uygun dosyaların da uygulamanın içerisinde bulunmasının istenmesinden kaynaklanmakta. Şu adreste de belirtildiği gibi uygulamada bulunması gereken icon dosyalarının tam listesi ve Info.plist dosyasına manuel olarak eklenmesi gereken icon dosyaları listesi aşağıdaki şekildedir.



Read More

MySQL Query Cache Ayarları

Daha çok okuma ve sorguya yönelik işlem yapan yazılımlarda kullanılan veritabanının aynı sorgulara vereceği cevapları kullanım sıklığına veya farklı algoritmalara göre saklayıp istemcilere tekrar sunması query cache olarak adlandırılır. Bir projede gerektiği için kullandığım ve sonrasında burada paylaşma gereği duyduğum mysql için query cache ayarları aşağıdaki gibidir. Bellek ve limit değerleri tamamen sisteme bağlı olup ancak çalışan bir sistem ve ayrılmış bir donanım üzerinde zamanla ayarlama ve testler yapılarak en çok performansı sağlayabilecek değerlere ulaşılabilir.

MySQL komut satırına giriş yaptıktan sonra query cache ayarları kontrol edilir.

mysql# show variables like 'have_query_cache';
+------------------+-------+
| Variable_name    | Value |
+------------------+-------+
| have_query_cache | YES   |
+------------------+-------+
1 row in set (0.03 sec)

şeklinde have_query_cache=YES olarak set edilmiş olmalıdır.
Geçerli query cache parametrelerini görmek için:

mysql# show variables like 'query%';
+------------------------------+----------+
| Variable_name                | Value    |
+------------------------------+----------+
| query_alloc_block_size       | 8192     |
| query_cache_limit            | 1048576  |
| query_cache_min_res_unit     | 4096     |
| query_cache_size             | 16777216 |
| query_cache_type             | ON       |
| query_cache_wlock_invalidate | OFF      |
| query_prealloc_size          | 8192     |
+------------------------------+----------+
7 rows in set (0.00 sec)

query_cache_size: byte türünden sistemde saklamak istediğiniz cache miktarı.
query_cache_type=ON/OFF olarak kapalı ya da açık olduğu bilgisi. 1 ya da 0 olarak da set edilebilir.
query_cache_limit= Cache için saklanacak bir sorgunun olabileceği maksimum büyüklük miktarı (byte)

Query cache 80MB kullanmak istediğimizde 10*1024*1024 = 83886080
mysql# SET GLOBAL query_cache_size = 83886080;
Query OK, 0 rows affected (0.06 sec)

mysql# show variables like 'query%';
+------------------------------+----------+
| Variable_name                | Value    |
+------------------------------+----------+
| query_alloc_block_size       | 8192     |
| query_cache_limit            | 1048576  |
| query_cache_min_res_unit     | 4096     |
| query_cache_size             | 83886080 |
| query_cache_type             | ON       |
| query_cache_wlock_invalidate | OFF      |
| query_prealloc_size          | 8192     |
+------------------------------+----------+
7 rows in set (0.01 sec)

mysql# SET GLOBAL query_cache_limit = 1048576;


Query OK, 0 rows affected (0.00 sec)

mysql# SET GLOBAL query_cache_type = 1;

Query OK, 0 rows affected (0.00 sec)

Bu ayarları reboot sonrası da saklamak ve etkinleştirmek için /etc/my.cnf dosyasına

query_cache_size = 268435456
query_cache_type=1
query_cache_limit=1048576

şeklinde ekleme ya da uncomment edilmiş satırları aktifleştirip değiştirmek yeterlidir.


Read More

PhoneGap İle IOS Uygulama Geliştirme

Phone Gap - Apache Cordova Nedir?

PhoneGap  Android, iOS, windows phone ve blackberry, bada gibi mobil platformlarda html,javascript,css gibi web geliştirme dil ve araçlarını kullanarak uygulama geliştirmeyi sağlayan ve aynı zamanda native APIlara ulaşmayı da sağlayabilen bir frameworktür. Geliştirilmeye başladığı ilk yıllara göre büyük gelişme gösteren framework, native uygulamalar yazarak müdahale edebileceğimiz ve geliştirebileceğimiz yazılımların tamamını bu tüm platformlar için bir defa geliştirme yaparak ve her platform için ayrı ayrı derleyerek çalıştırma imkanı sunar. Android veya iOS geliştirmek için geliştiricinin java ya da objective C bilmesine gerek kalmadan bir üst seviyede tasarımın ve mantıksal yapının html,javascript ile oluşturulmasına dayanır. Native uygulamaların performansı ve güvenilirliği her zaman için daha yüksek olsa da geliştirilecek uygulamanın isterlerine göre bu tip frameworklerle de geliştirmeler tamamlanabilir ve bazen çok da hakim olunmadan native kod ile geliştirilecek uygulamalardan daha performanslı ve güvenilir olabilir.

PhoneGap bir süre önce Adobe tarafından satın alınmış ve 5 mobil platformda html,css,javascript ile platform native APIlarına erişim sağlayabilen bir framework olarak tasarlanmıştır. Satın alma sonrasında ise Apache Cordova olarak Apache Software Foundation altında geliştirilmeye devam edilmiş ve Adobe tarafından ayrıca geliştirilecek ve eklenecek pluginler yine PhoneGap olarak devam edecektir. Her iki framework de başlangıç için sadece isminin değiştirilmesi ile ortaya çıkmış olsa da ilerde PhoneGap tarafında Adobe eklentileri görülebilir. PhoneGap ve Apache Cordova her ikisi de ücretsiz ve açık kaynak kodlu olarak sunulmaktadır. Çok farklılıklar olmasa da uygulamada PhoneGap ya da Apache Cordova kullanırken bazı küçük farklılıklar oluşabilmektedir. Platform olarak önceden de kullandığım için PhoneGap ile devam etmeyi düşünüyorum ve örneklerde de PhoneGap kullanarak devam edeceğim.

Not: Tutorialler boyunca $ simgesi komut satırında yazılması gereken komutları simgeler ve komut satırında ayrıca $ karakterinin yazılmasına gerek yoktur.

PhoneGap Kurulumu

  1. Öncelikle sistemimizde node.js kurulu olmalı. Eğer kurulu değilse nodejs.org/ adresinden indirip yükleyebiliriz. Kurulum sonunda komut satırında npm komutunu bulabilmeli. MacOs için .pkg dosyasını indirip kurmak yeterli oldu. Farklı işletim sistemleri için belki sistem path değişkenine ekleme yapmak gerekebilir.
  2. Phone Gap Kurulumu adımında npm ile phonegap kurulumu neredeyse saniyeler içerisinde kolayca yapabileceğimiz bir işlem.
    $ sudo npm install -g phonegap
    komutu ile phonegap'i sisteme kurabiliriz. İşlem sonucunda komut satırından "phonegap" komutunun çalışıyor olması gerekmekte. Yine farklı platformlar için ayarlar gerekebilir.

Proje Oluşturma

Phone Gap kurulumu sonrasında projeyi oluşturacağımız kök dizine gidip komut satırınında bu dizini açıyoruz.
  1. $ phonegap create sampleapp com.onuratci.ios.sampleapp SampleApp
    komutu ile sampleapp dizininde com.onuratci.ios.sampleapp paket adı ile uygulama adı SampleApp olan bir uygulama oluşturmuş oluyoruz. Bu değerler daha sonradan değiştirilebilir ama yine de başlangıç için paket adını ve dizini uygun vermek işimizi kolaylaştıracaktır.
  2. Yukarıdaki adımda oluşturduğumuz uygulamamızın bulunduğu dizine geçip hangi platformlar için geliştirme yapacaksak bu platformların desteğini ekliyoruz. Ben sadece ios ile devam edeceğim için şimdilik sadece ios build ile ios desteğinin eklenip projenin build edilmesini sağlıyorum.
    $ cd sampleapp
    $ phonegap build ios
    Şu şekilde bir ekran çıktısı görüyor olmamız gerekli:
    [phonegap] detecting iOS SDK environment...
    [phonegap] using the local environment
    [phonegap] adding the iOS platform...
    [phonegap] compiling iOS...
    [phonegap] successfully compiled iOS app
  3. Bu aşamadan sonra uygulama dizini içerisindeki platforms/ios/ dizini XCode ile open project menüsünden açılabilir.
  4. Projeyi Run -> IPhone6 Simulator seçerek XCode içerisinden çalıştırabiliriz.
  5. Eğer herhangi bir simulatör kurulu değilse öncelikle sisteme simulatör eklememiz gerekir. Bunun için XCode-> Preferences->Downloads kısmından ilgili simülatorler kurulabilir.

Pluginleri Etkinleştirmek

Uygulama içerisinde native apileri kullanmız gerektiğinde öncelikle ilgili pluginin phonegap ile projeye eklenmesi gerekir. Örnek projemizde network durumunu görüntülemek istediğimizi düşünelim. Terminal uygulaması ile ilgili proje dizinine geçip aşağıdaki komut çalıştırıldığında projeye Network plugini tanımlanacaktır.
$ phonegap local plugin add https://git-wip-us.apache.org/repos/asf/cordova-plugin-network-information.git
Tüm eklenebilecek özellikleri ve adreslerini görebilmek için şu linkteki Add Features kısmına bakılabilir.

Projede Bazı Değişiklikler Yapmak

Bu aşamaya kadar phonegap kurulum ve diğer araçlar ile genel proje yapısı anlatıldı. Bu aşamada uygulamayı emülatörde çalıştırdığımızda şöyle bir ekran görürüz.

Proje dizininde index.html dosyasına ekleyeceğimiz  


kodları ile projede ilk değişikliği yapmış oluruz. 
Ekran görüntüsü:


Ek Bilgi:
Uygulamanızı app store'da yayınlayacağınız zaman birçok boyutta uygulama icon dosyasını da temin etmeniz gerekir. Bu iconları tek bir icon kullanarak oluşturmak isterseniz yapmanız gereken 1024*1024 boyutunda kaliteli olarak çalışılmış uygulama iconunuzu http://makeappicon.com/ adresine yükleyerek gerekli tüm boyutlarda hazırlanan arşiv dosyasını indirmek. Bu sayede saniyeler içerisinde icon boyutları ile ilgili sorunu aşabilirsiniz.
Read More

Nginx Anlık Bağlantı Durumunu Görüntüleme

Nginx apache web sunucusuna göre aktif/pasif bağlantıları yönetmede ve hem statik hem de php modülü ile çalıştırılması gereken sayfalarda gösterdiği performansla uzun zamandır tercih ettiğim bir sunucu modülü olmuştur.
Anlık olarak ve toplamda Nginx sunucusunun durumunu izleyebilmek de bazı zamanlarda önemli olabilir. Bu amaçla belki daha farklı raporlama araçları olsa da çoğu durum için Nginx'in kendi modülü olan HttpStubStatusModule çoğu ihtiyacımı karşılayabilen bir araç olmakta. Basit olarak aktive edilişini ve parametrelerin hangi anlamlara geldiğini kısa notlar halinde paylaşıyorum.

Öncelikle sistemde bulunan nginx kurulumumuzda httpstubstatusmodule ile birlikte derlenip derlenmediğini tespit edebiliriz:
# nginx -V
--with-http_stub_status_module modülünü ekranda görüyorsak bu modülü kullanabileceğimiz anlamına gelir.
Nginx ile görüntülemek istediğimiz sanal ya da varsayılan siteye /nginx_status adresinden yayınlanacak şekilde rapor konumunu ekleyebiliriz.
# nano /etc/nginx/hosts.d/default.conf 
Aşağıdakileri uygun şekilde yukarıdaki dosyanın sonuna location tanımlamaları sonuna ekliyoruz.
location /nginx_status {
stub_status on;
access_log off;
#sadece kendimiz erişmek istiyorsak (önerilir!)
allow 192.168.1.100; #raporu görüntüleyeceğimiz IP adresini yazıyoruz.
#her adresten erişmek isteniyorsa aşağıdaki satırdaki # kaldırılmalı.
#allow all;
deny all;
}
Dosyayı kaydedip 
nginx -reload
komutu ile nginx sunucunu ayarları yeniden okuyacak şekilde çalıştırıyoruz. Burada nginx durdurulmadan ayarlar okunduğu için ayarlarda bir sorun varsa sunucu durmadan bize gerekli uyarıyı verecektir. Yeniden dosyayı düzenledikten sonra yeniden reload komutunu verebilir ve isteğe bağlı olarak nginx -restart ile servisi kapatıp açabiliriz.
curl http://localhost/nginx_status
komutu ile ya da sunucumuzun IP adresi ile nginx_status sayfasını alabiliriz.  Bu sayfa içeriği şu şekildedir:
Active connections: 11
server accepts handled requests
 293863 293863 353057
Reading: 5 Writing: 1 Waiting: 5
Active connections: Sistemde o anda açık olan tüm bağlantıların sayısı. (11)

Reading: Nginx'in request başlığını okuduğu toplam istek(request) sayısı (5)

Writing: nginx'in request body okuduğu ya da request işlediği veya request sonucunun istemciye yazdığı istek sayısı (1)

Waiting: Nginx sunucunda keep-alive olarak bağlı tutulan ama aktif olarak read/write işleminde olmayan bağlantı sayısı. (5)

Active Connections  = Reading+Writing+Waiting
(11 = 5 + 1 + 5)

Server Accepts: Sunucunun kabul ettiği toplam bağlantı sayısı (293863)
Handled: Sunucunun işlediği ve cevap verdiği toplam bağlantı sayısı (293863)
Requests: Sunucuya bağlantılar üzerinden gelen toplam istek(request) sayısı (353057)


 
Read More

Android Target SDK ve Option Menu

Android ICS sürümünde duyurulan yeniliklerden birisi de seçenekler menüsünün (option menü) kaldırılması olmuştu. Sebebi ise yenilenen title bar ile zaten options menünün üst kısma taşınmış olmasıydı. Fakat uygulamanız standart title bar içermiyor ya da tam ekran olarak çalıştırılıyorsa burada yine kendi oluşturduğunuz eski stil option menu ihtiyacınızın devam ettiği anlamına geliyor.
Burada standart bir action bar içermeyen uygulamanızın android 3.0 ve üzeri versiyonu çalıştıran cihazlarda option menu ile görüntülenmesi için android.manifest dosyasında target-sdk değerini 11den daha düşük bir versiyonda tutmanız yeterli.
Read More

X Günden Daha Eski Dosyaları Silmek

Bazen sunucuda ya da sistemimizde belirli bir zamandan önceki dosyaları silmemiz gerekebilir. Bu bazen kullanilmayan cache dosyaları olurken bazen süresi dolan session tokenları olabilir.

Burada +3 ile 3 gün öncesindeki dosyaların bulunup her dosya icin exec rm cagrilmaktadir. find komutu ile gün ya da dakika icin mtime/ctime komutlarina daha detaylı bakabilirsiniz.

find /silinecek/dosyalar/dizini/* -mtime +3 -exec rm {} \;

Gerekli durumlarda belirli süreler için bu scriptin tekrar çalıştırılması gerekiyorsa linux cronuna ekleyerek belirli bir aralıkta çalışmasını sağlayabilirsiniz.
Read More

Tek Satır Script İle Web Server

Bir satır kabuk scripti ile http server kullanmadan bir dosyayı http protokolü ile sunmanın yolu: kaynak

Netcat kullanarak:

while true; do { echo -e ’HTTP/1.1 200 OK\r\n’; cat index.html; } | nc -l 8080; done
Read More

Android İçin İlk Uygulamamız: Merhaba Android

Bu yazımızda geçen yazıda incelediğimiz uygulama bileşenlerinin ve olay yakalama metodlarının çok az bir kısmını kullanarak android uygulamalarına merhaba diyeceğiz. Çok basit bir uygulama olarak programda merhaba android yazısını çıktı olarak görmeye çalışacağız. Android geliştirme ortamınızın önceki yazımızda belirtildiği şekilde çalışmaya hazır ve uygulamaların nasıl çalıştığı hakkındaki yazımıza da göz atmış olduğunuzu varsayarak işe başlıyoruz.

Uygulamamızı geliştirmeye başlarken Android ADT Plugin eklenmiş Eclipse 3.5 Galileo 'yu başlatıyoruz. File--->New--->Android Project izleyerek yeni bir android projesi oluşturuyoruz. Ekran görüntüleri çalışma ortamına uyum sağlamakta zorlandığınız noktalarda yardımcı olabilir. Sonraki yazılarımızda bu kadar çok ekran görüntüsü vermeyi düşünmüyorum.
Burada bazı özellikleri belirlememiz gerekiyor. Uygulamamızın çalışacağı hedef platformu sdk paketimizde yüklü olanlar arasından seçiyoruz. Uygulama adı olarak uygulamamızın adını giriyoruz. Paket adı kısmı ise javadaki paketleme mantığıyla çalışan ve sınıflara erişimde kolaylık ve aynı zamanda dosya sistemi olarak hiyerarşik bir düzen sunan kelimeler girmemizi bekliyor. CreateActivity kısmında  uygulamamızın temel bileşenlerinden birisi olacak aktiviteye bir isim verilmesi gerektiğinin belirtildiği alandır.Her android uygulamasının en az bir activity'e sahip olması gerekir. Yukarıdaki gibi bir proje oluşturduktan sonra Finish butonuna tıklıyoruz ve artık projemizin oluşturulduğunu package explorerdan görebiliyoruz.Projeye başlamadan önce Project->Clean tıklayarak projemizde oluşmuş hataları temizliyoruz.
Yazacağımız uygulamada çok fazla android API kullanmayacak olsak da genel olarak package explorerda gördüğümüz tüm paketleri tanımlamaya çalışacağız.
Kod Kaynak Dosyaları(/src):  Verdiğimiz paket hiyerarşisine göre uygulama kodlarının dosyalar halinde bulunduğu klasördür.
Otomatik Oluşturulan Dosyalar(/gen): Oluşturduğumu activity için  java şablonunu içeren R.java dosyasını içerir. (Resource References) Bu dosya her proje oluşturulurken SDK tarafından oluşturulur ve res klasöründeki tüm kaynaklara referanslar içerir.
Android 1.5: Android kütüphanesidir.SDK tarafından uygulamada kullanılacak framework dosyaları ve tüm sınıflar buraya yüklenir.  Android.jar ağacı genişletilirse içerdiği tüm paketler ve sınıflar görülecektir.
Assets: Uygulamaya gömülü olarak dağıtmak istediğimiz paketleri buraya koyabiliriz. Şimdilik bu uygulama için herhangi bir ek pakete ihtiyacımız yok.
Kaynaklar(/res): Uygulama tarafından kullanılan tüm nesneler burada bulunurlar. Görsel ögelerin hepsi drawable klasörü altında, uygulamanın yerleşim (layout) düzeni layout altındaki main.xml dosyasında xml formatında, string , sabit değerler ve diğer değişkenler values altında toplanırlar.
Manifest Dosyası(AndroidManifest.xml): Manifest dosyası en önemli dosyalardan birisidir. Android build sistemi uygulama hakkındaki birçok önemli bilgiye bu xml dosyasından ulaşır. Uygulamanın çalışmasında izinlerde ve birçok konuda bu dosyada tutulan veriler kullanılır.

Şimdi yukarıdaki bilgileri de elde ettiğimize göre src klasörü altındaki activity koduna bakabiliriz.

package com.blogspot.androidgelistir;

import android.app.Activity;
import android.os.Bundle;

public class merhabaactivity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }
}


Yukarıda merhabaactivity.java dosyasının tam içeriği görüntülenmektedir. Paket ve import statementlarına java programlama dilinden alışık olduğumuzu düşünerek burayı açıklamadan geçiyorum.Buradan merhabaactivity sınıfının activity sınıfından türetilerek kullanıldığını anlıyoruz. onCreate() metodunun override edilerek kullanılabileceğini geçen yazımızda belirtmiştik ve burada da @Override annotation'ı  ile metodun yeniden yazıldığını görebilirsiniz. onCreate() metodu uygulama bellekte ilk defa oluşturulduğunda çalıştırılan bir metod olduğu için devamında türetilen sınıfa ait onCreate() metodunu çağırarak (bknz java super) eğer aynı uygulamadan çalışmakta olan kopyalar varsa o uygulama verilerini yeni oluşturulan uygulamada kullanmak için kullanılır.
setContentView(R.layout.main) satırı ile androidin ekran nesnelerini yerleştirirken layout altındaki main.xml dosyasını kullandığını söylemiştik. Burada  içerik görünümünü ve yerleşimi main.xml e göre yapılacak şekilde ayarlanıyor.
Şimdi de layout altındaki main.xml dosyasına bakalım.

Xml tanımlama başlığı her dosyada bulunması gereken bir satır olarak yine yerini almış. LinearLayout javadaki yerleşim stillerine benzer şekilde android üzerindeki layout türlerinden en basiti ve şu an için bize yeterli olanıdır. TextView ise görüntülenebilir ve düzenlenebilir text alanı sunan bir kontroldür. android:text="@string/hello" satırı bize TextView nesnesinin görüntüleyeceği text'in dışarıdan bir resource olduğunu ve string dosyasında olacağını ayrıca isminin de hello olacağını söylüyor. Gerçekten de resources klasörü altındaki values klasörü içindeki string.xml dosyasına eclipse package editör üzerinden tıklarsak ADTnin bize sunduğu özel bir editörle bu değeri görebiliriz ve değiştirebiliriz. 
Burada uygulamanın hello değişkenine ait değerini "Merhaba Android" olarak değiştiriyoruz. Böylece TextView'in gösterdiği değer de değişmiş olacak.
Ayrıca uygulama adını da string.xml dosyasındaki app_name değerini düzenleyerek değiştirebiliriz.

Uygulamanın Çalıştırılması:
Tüm yapılan değişiklikleri kaydettikten sonra artık test sürüşüne çıkabiliriz. Bunun için package explorer da uygulamanın kök dosyası/dizini seçiliyken (bu uygulama için MerhabaAndroid olacaktır) Run->Run'a tıklıyoruz. Burada bir Run-As dialog penceresi açılabilir. Buradan Android Application 'ı seçerek ilerliyoruz. Eğer burada hata mesajı alırsanız Project->Clean seçerek projeyi tekrar build etmeyi deneyebilirsiniz. Eclipse önceden seçtiğimiz sanal aygıta projeyi gönderecek ve çalıştıracaktır.
Uygulama ismini ve TextView üzerinde yaptığımız değişiklikleri emulator üzerinde gördük. Merhaba Android uygulamamızın sonuna geldik. Bir başka uygulamada görüşmek üzere.
Read More

Android Uygulamalarının Bileşenleri ve Bileşenlerin Yaşam Döngüsü

Android için uygulama geliştirmeye başlamadan önce ilk olarak uygulamaların nasıl çalıştığına ve hangi kısımlardan oluştuğuna bakmakta yarar vardır. Çünkü her uygulamanın bir yaşam döngüsü vardır, bir sistem üzerinde geliştirilen  uygulama çeşitleri vardır ve en önemlisi de sistemin bu uygulamaları işletme ve zaman içerisinde sistem kaynaklarını yönetme şekli vardır. Windows ya da linux nasıl uygulamaları ve prosesleri bellekte ve diskte belirli algoritmalara göre tutuyor ve yönetiyorsa, android sistemi de uygulamaları ve diğer platformlara göre daha çok sınırlı olan sistem kaynaklarını yönetir.

Android Uygulamalarının Bileşenleri:
Geliştireceğimiz android uygulamaları 4 temel kısım üzerine inşa ediliyorlar. Bu temel kısımlar;
  1. Aktiviteler(Activities): Aktiviteler çalıştırılabilir kodun belirli kısımlarını oluşturan ve zamanın belirli bölgelerinde kullanıcı ile ve sistemle etkileşime geçerek gerekli veriyi  sağlayan, sonunda da kullanılmadıkları zaman sistem tarafından sonlandırılan parçalardır.
  2. Servisler (Services): Servisler bilgisayarlardan da tanıdık olduğumuz arkaplanda çalışan ve uygulamanın bir parçası olan kısımlardır. Aygıt kapanana kadar arkaplanda hazır olarak çalışırlar.Genellikle kullanıcı arayüzü olarak sunulmazlar. Uygulamaların ihtiyacı olan verilerin ve hizmetlerin sağlanmasında kullanılırlar.
  3. Broacast and Intent Receivers: Broadcasting işlemi bilinen broadcast uygulamaları gibi aygıtın temel mesajlarının tüm sisteme gönderilmesidir.Düşük pil uyarısı yada zaman dilimi değiştirilmesi gibi olaylarda aygıt, uygulamaların tümünü bu durumlardan haberdar eder. Intent receivers ise belirli bir amaca göre bazı varolan uygulamalardan ve servislerden bilgi toplanmasıdır. Varolan bir uygulamayı kullanarak uygulama geliştirildiğinde bu tür olay yakalayıcılar kullanılır.
  4. İçerik Sağlayıcılar(Content Provider): Aygıt üzerindeki uygulamalar dosya sisteminde yada dosya sistemi üzerindeki SQLite veritabanı üzerinde uygulamaya ait verileri saklarlar. Diğer uygulamaların da belirli veri tiplerine uygun olarak bu verileri kullanabilmesi Content Provider ile sağlanır. Content provider uygulamalara bu verilere erişim için bazı metodlar sunar. 
Kısaca uygulamamızı oluşturan önemli temel kısımları incelemiş olduk. Bu kısımların nasıl çalıştığına ve yaşam çevrimlerine bakacak olursak uygulama geliştirirken bileşenlerin rolleri hakkında daha net bilgi sahibi olabiliriz.

Bileşenlerin Aktifleştirilmesi: 

Bir aktivite Context.startActivity() ve Activity.startActivityForResult() methodları ile aktifleştirilir. Burada intent nesnesi karşımıza çıkar.  Intent nesneleri broadcast receiversi servisler ve aktiviteleri aktifleştiren asenkron mesajlardır. Intent nesneleri mesaja ait bilgileri saklar.  Örnek olarak aktivite ve servisler için isteğin yapıldığı durumu ve verinin konumunu tutabilir.Aktivitelerin aktifleştirilmesi için de Intent nesnelerinin yukarıdaki metodlara parametre olarak geçilmesi gerekir. Eğer aktivitenin sonuç döndürmesi bekleniyorsa Activity.startActivityForResult() metodu kullanılır. Aksi halde Content.startActivity() metodu kullanılır.
Bir servis ise Context.startService()  metoduna Intent nesnesinin parametre olarak geçilmesiyle aktifleştirilir. Burada android onStart() methodunu çağırır(Intent nesnesini bu metoda göndererek) ve servis başlatılmış olur.  Aynı şekilde Context.bindService() metodu ile dedevam eden bir bağlantıya tekrar devam edebilir.
Bir uygulama broadcast mesajları göndermek için Intent nesnesini context.sendBroadcast() context.sendOrderedBroadcast() context.sendStickyBroadcast() metodlarından birisine gönderebilir.

Bileşenlerin Durdurulması:
Bir Content Provider, Content Resolver'a cevap verdiği sürece aktiftir. Aynı şekilde broadcast receiver bir broadcast mesajına cevap verdiği sürece aktiftir. Yani kesin olarak bu bileşenlerin kapatılması gibi bir durum da yoktur. Aktivite ve servisler ise farklıdır ve özel metodlarla bu bileşenler durdurulur. Aktivite finish() metodu ile durdurulur. Bir aktivite diğer bir aktiviteyi durdurabilir. Bunu yaparken finishActivity() metodunu kullanır. Bir servisin kapatılmasında ise stopSelf() veya Context.stopService() metodlarını çağırmak gerekir.

Manifest Dosyaları:
Android uygulamaları başlamadan önce hangi bileşenlerden oluşuyor olduğunu bilmelidir. Bu sebepten dolayı Android uygulamaları android uygulama paketi içinde gömülü olarak manifest dosyasını bulundurmalıdır. .apk dosyasında ayrıca uygulama kodu, dosyaları ve kaynaklar bulunabilir.
Manifest dosyası XML formatındadır ve her android uygulamasında AndroidManifest.xml olarak bulunur. 

Bileşen Yaşam Döngüleri:
Uygulama bileşenleri bir yaşam döngüsüne sahiptirler. Uygulamalar başlangıç ve son arasında aktif ve inaktif modda olabilirler. Bu modlar arası geçişte uygulama sonlandırılabilir ya da  yokedilebilir. 

Aktivite Yaşam Döngüsü: 
 Bir aktivite 3 duruma sahip olabilir;




    • Aktif ya da çalışır durumda uygulama kullanıcıya odaklanmıştır ve kullanıcıdan gelecek verilere göre sonuçlar üretilir.
    • Bekleme modunda başka bir uygulama çalışmaya başlamış, uygulama arkaplana itilmiş fakat aynı şekilde çalışmaya devam etmektedir. Uygulama bekleme modunda düşük bellek durumlarında sistem tarafından yokedilebilir.
    • Durdurulmuş durumda uygulama tamamen çalışmaz durumdadır buna rağmen en son verilere sahiptir. Uygulamaya ayrılmış bellek sistem tarafından gerektiğinde kullanılabilir. 
Aktivite bir durumdan diğer duruma geçerken aşağıdaki metodları çalıştırır.(hook)

void onCreate(Bundle savedInstanceState)
void onStart()
void onRestart()
void onResume()
void onPause()
void onStop()
void onDestroy()


Bu durum geçişlerinde yapacağımız işlerde yukarıdaki metodları override ederek kullanabiliriz. Tüm aktiviteler onCreate() metodunu implement etmek zorundadırlar. Ayrıca çoğu uygulama onPause() metodunu da implement edecektir.
Uygulamanın tüm yaşamı onCreate() ile onDestroy() arasındaki geçen zaman arasındadır.
Uygulamanın yaşam döngüsü hakkındaki şemayı dökümantasyon web sitesindeki hali ile vermeyi uygun gördüm. Aşağıdaki şemada durum geçişleri ve metodlar görülebilir.

Şimdi kısaca geçiş durumu metodlarını ve yaşam döngüsündeki sıralamalarına bakalım;
onCreate():Aktivite ilk defa çalıştırıldığında çalışan metod. onCreate() sonrasında her zaman onStart() metoduna geçiş yapılmış olur.
onRestart(): Aktivite onStop() ile durdurulduktan sonra yeniden başlatıldığında  geçilen durumda çalıştırılan metoddur. Bu metodu onStart() metodu izler.
onStart(): Uygulama kullanıcıya uygun hale geldiğinde çalıştırılan metoddur. Aktivite önplanda çalışmaya başlayacaksa onResume(), gizlenecekse onStop() metodu bu metodu izler.
onResume(): Aktivite kullanıcı ile etkileşime geçmeden önce çalıştırılan metoddur. Sonrasında kullanıcı uygulamayı kullanmaya başlar. Sonrasında her zaman onPause() metodu izler.
onPause(): Android diğer bir uygulamaya devam edeceği zaman geçilen durumda çağrılan metoddur. Bu metod ile uygulama kaydedilmemiş verileri kaydeder ve animasyonları durdurma gibi birçok farklı işlemi yapar. Eğer uygulama devam edecekse bu metodu onResume() izler. Eğer uygulama durdurulacaksa onStop() metodu ile devam edilir.
onStop(): Uygulama durdurulduğunda bu metod çalıştırılmış olur. Bu durum geçişinden sonraki gelebilecek durumlar uygulamanın tekrar çalıştırılması, onRestart() ya da uygulamanın tamamen kapatılması ,onDestroy() metodunun çağrılmasıdır.
onDestroy(): Uygulama yokedilmeden önce çağrılan metoddur. Bu çağrı yapılacak son çağrıdır ve sonrasında uygulama bellekten gerektiğinde silinecektir.
onDestroy() , onStop() ve onPause() durumlarında uygulama sistemin belleğe gereksinim duyması durumlarında tamamen bellekten yokedilebilir. Bu durumu göz önüne almak gerekir.

Servis Yaşam Döngüsü:
Servisler kullanım biçimi olarak iki şekilde kullanılabilirler.
  • Herhangi birisi tarafından başlatılıp sonlandırılmasına izin verilebilir. Bu durumda uygulama servisi Context.startService() metodu ile başlatır ve Context.stopService() metodu ile sonlandırır. Ya da servis kendini Service.stopSelf() ya da Service.stopSelfResult metodlarıyla sonlandırabilir.
  • Diğer modelde ise programatik olarak bir arayüz kullanılarak bu işlemler gerçekleştirilebilir. Kullanıcılar Context.bindService()  metoduyla servise bağlantıyı sağlayabilir ve Context.unbindService() metodu ile servisle bağlantısını kapatabilir. Bu bağlantı yönteminde birden çok client eş zamanlı olarak bağlantı açıp bağlantı kapatabilir. 
Ayrıca bu modellerde önce startService() metodu ile servis başlatılıp yeniden servisin kullanımına ihtiyaç duyulduğunda bindService() metodu kullanılabilir. Bu durumda da tüm clientlar bağlantıyı kapatana kadar yapılan stopService() metod çağrıları bağlantının kapanmasını bekleyeceklerdir.Yine servisin yaşam döngüsündeki durumları arasında geçiş yaparken çalıştırılan metodlar mevcuttur;   
void onCreate() 
void onStart(Intent intent) 
void onDestroy() 
IBinder onBind(Intent intent) 
boolean onUnbind(Intent intent) 
void onRebind(Intent intent)


Her servisin yaşam döngüsü onCreate() ile başlar ve onDestroy() metoduna kadar devam eder. Aktif olarak servisin çalıştığı kısım ise onStart() metodu sonrasıdır.

Broadcast Receiver Yaşam Döngüsü:
Bir broadcast mesajı alıcıya ulaştığında android onReceive() metodunu çağırır ve Intent nesnesini mesajı da içeren bir şekilde bu metoda aktarır. Broadcast Receiver  bileşeni tek metodu olan onReceive() çalışıyorken aktif olarak kabul edilir. Diğer zamanlarda broadcast receiver inaktiftir.
void onReceive(Context currentContext, Intent broadcastMessage)

Buraya kadar olan kısımda uygulamaların genel özelliklerini inceledik. Bu kısımların anlaşılması ilk zamanlarda biraz zor olsa da uygulama geliştirmeye başlamadan önce bazı temel bilgileri önceden almak ilerde uygulama geliştirme konusunda karşılaşılan sıkıntıları en aza indirecektir. Gelecek yazımızda görüşmek üzere.
Read More

Android Geliştirme Ortamının Kurulması

**Bu yazımızda Android sistemler için yazılım geliştirmede kullanılan ortamın hazırlanmasını inceleyeceğiz. Android Google tarafından geliştirilen ve desteklenen bir sistem olduğundan dolayı her platform üzerinde geliştirme yapmaya imkan veren araçlara uygun olarak hazırlanmıştır. Temel geliştirme araçları Android SDK, Eclipse 3.5 , Eclipse ADT Plugin’ den oluşmaktadır. Şu an Eclipse Helios (3.6) dağıtılıyor olsa da bilinen sorunlardan dolayı 3.5 Galileo sürümünün kullanılması gerekmektedir. Bu yazımızın sonunda android üzerinde yazılım geliştirmeye hazır bir ortama sahip olacağız.

Öncelikle indirmemiz gereken araçları bağlantıları kullanarak indiriyoruz.

1. Android SDK : Hangi platformda çalışacaksak o platforma göre belirlenmiş SDK’yı indiriyoruz. İlerleyen kısımları Windows işletim sistemleri için anlatacağım fakat Linux ve MacOS X için de çok farklılık olduğu söylenemez.
http://developer.android.com/sdk/index.html


Buradan windows için http://dl.google.com/android/android-sdk_r06-windows.zip konumundaki dosyayı indiriyoruz. Diğer dağıtımlar için de yukarıdaki adresten  indirmelere göz atabilirisiniz.
2. JDK Kurulumu:
http://java.sun.com/javase/downloads/index.jsp  adresinden güncel Java Development Kit’i indirip kuruyoruz.
3. Eclipse Kurulumu:
Eclipse 3.5 Galileo paketini http://www.eclipse.org/downloads/packages/release/galileo/sr2 adresinden indirip arşivi bir dizine açıyoruz.(Ben D:\Development\Eclipse konumuna açtım.) Eclipse Java veya JavaEE paketlerinden birisini indirebilirsiniz. Eclipse Helios sürümüyle SDK çalışmasında sorunlar oluştuğu için SDK adresinde bildirilene kadar Android geliştirme için eclipse 3.5 kullanacağız.
4. Eclipse ADT Plugin Kurulumu:
Eclipse ile android uygulamaları geliştirmek için ADT plugin kurulu olması gerekiyor. Kurulumda iki farklı yol izlenebilir. İlk olarak ADT plugin dosyasını http://dl.google.com/android/ADT-0.9.7.zip adresinden indirip Eclipse’de Help-> Install New Software izlenerek açılan pencerede Add butonuna tıklayarak isim kısmına Android ADT , adres (location) kısmında da Archive butonuna tıklayarak indirdiğimiz dosyanın yolunu girebiliriz. Ya da Location için https://dl-ssl.google.com/android/eclipse/  adresini girebiliriz.
 Sonrasında iki adet paket bulunacaktır. DDMS ve Development Tools seçip ilerliyoruz.

Bu adımlardan sonra ADT kurulumu tamamlanmış oluyor.
Şimdi Eclipse – Android SDK uyumunu sağlamak için son adım olan Android SDK ayarlarına geçebiliriz.
Android SDK’yı arşivden çıkardığımız dizine gidiyoruz ve SDK Setup’a tıklıyoruz.


Öncelikle karşımıza güncellemeleri denetleyen bir pencere çıkacaktır ve hata verecektir. Burada “settings”  kısmına gelerek https kaynaklarını http olarak kullanmayı etkinleştirmemiz gerekiyor. Bu işlem sonucunda güncellemeleri tekrar denetleyen bir pencere açılır ve güncellemeler gösterilir. İlk etapta güncellemeleri kurmadan ilerleyebilirsiniz.


Available packages’a tıklayarak o anda mevcut SDK Platformlarına göz atabiliriz.


Buradan eğer kota probleminiz yoksa SDK Platform 2.2, 2.1, 1.6, 1.5 sürümlerini ve dökümantasyonu işaretleyebilirsiniz. Ya da sadece 1.5 sürümünü işaretleyebilirsiniz.


Burada mevcut internet bağlantısına göre biraz beklemeniz gerekebilir. Bir kahve alıp ara vermek iyi bir fikir olacaktır.


Kurulum işlemi bittiğinde kurulan paketleri installed packages altında görebiliriz.
Artık bu adımdan sonra SDK kurulumu da tamamlanmış oluyor. Sanal aygıtı oluşturup sanal makinayı kurcalayarak android geliştirme dünyasına adım atmış olacağız. Sanal aygıt oluşturmak için Virtual Devices ‘a tıklıyoruz. New butonuna tıklayarak açılan pencerede sanal aygıt ayarlarını yapacağız.



Kurduğunuz platform versiyonlarına göre target kısmında hangi android os versiyonuyma çalışacağımızı seçiyoruz. SD kart  1000 mb değeri ile SD kart depolama kapasitesini belirliyoruz. Create AVD butonuna tıklayarak işlemi tamamlamış oluyoruz.


Artık Virtual Devices kısmından bir sanal aygıt seçerek start butonuna tıkladığımızda sanal android aygıtımızı kullanabiliriz.
Eclipse ortamına tekrar dönerek kalan işlemleri tamamlıyoruz. Window-> Preferences altında Android kısmına tıklıyoruz.


SDK location kısmına az önce ayarladığımız SDK klasörünün adresini yazıyoruz. Apply butonuna tıkladığımızda SDK üzerinde kurulu olan platformlar listelenecektir.


Bir hedef plaftorm seçerek OK butonuna tıklıyoruz. İşlem tamamlanmış oldu.
Böylece Google Android SDKyı kurmuş sanal aygıt oluşturmuş ve Eclipse ortamını uygulama geliştirmeye hazır hale getirmiş olduk. Sonraki yazımızda hazırladığımız bu ortamı kullanarak ilk android uygulamamızı yazacağız ve sistemin çalışma mantığını kavramaya çalışacağız. Şimdilik hoşçakalın.
Notlar:
*Yazının devamında ve Android geliştirme konularında önceden Java ve Eclipse IDE konusunda bazı temel bilgilere sahip olmanız gerekmektedir. Bu konularla ilgili sorunlarda temel java ve eclipse yardım dökümanlarına göz atabilirsiniz.
**Windows kullanıcı adınız Türkçeye özel karakterler(ç,ş,ğ,ı) içeriyorsa sanal aygıt çalışmayacak ve config.ini bulunamıyor hatası verecektir. Bu durumda yeni bir kullanıcı hesabı oluşturmanız gerekir.
***Yukarıdaki işlemleri Eclipse 3.6 sürümü ile de yapabilirsiniz fakat bu sürümde xml configuration dosyaları hata verecek ve IDE hatalara yol açacaktır.
****Yukarıdaki gereken dosyaları indirirken sorun yaşıyorsanız Google sunucuları Türkiye’de IP engellemesi sorunu yaşıyor olabilir, bu dosyaları indirebilmek için TOR kullanmanız gerekebilir.
Read More

Android Nedir?

Android cep telefonlarını ve diğer mobil aygıtları en az günümüz bilgisayarları kadar kullanışlı hale getirebilmek için başlatılan ve açık kaynak kodlu ilerleyen bir mobil işletim sistemi projesidir. Open Handset Alliance tarafından 12 Kasım 2007 tarihinde Google Android SDK olarak dağıtıldı. Alanında  büyük yenilikler getiren Android, sadece cep telefonları için bir işletim sistemi değil aynı zamanda netbooklar üzerinde de
kullanılabilecek bir sistemdir. Android linux kerneli kullanılarak geliştirilmekte ve özelleştirilmiş bir java sanal makinası ile uygulamaları çalıştırmaktadır. Kullanıcılar için internet ve mobil uygulamaları kullanma konusunda sağladığı bir çok kolaylığın yanısıra geliştiricilere verdiği ücretsiz ve açık bir ortamla kolay yazılım geliştirme imkanları sunmaktadır.


Linux kernel version 2.6 üzerine inşa edilmiştir ve Google tarafından Dalvik Virtual Machine adı verilen (DalvikVM) özel bir JVM çalıştırır. Bu sanal makina mobil aygıtlar için bellek ve işlemci optimizasyonları getiren bir sistemdir. Dalvik sanal makinasının java sanal makinasından en büyük farkı stack tabanlı çalışan JVM’in aksine Dalvik sanal makinasında register’lar için optimize bir sistemin kullanılmasıdır. Mobil aygıtlarda register’lar çok verimli veri işleme sağlarlar ve Dalvik VM registerlar üzerinde çalışması için üretilmiştir. Android sistemi üzerinde sistem uygulamaları ve 3. parti yazılımlar aynı kısıtlarla çalışırlar. Örnek olarak yeni bir program kurabilirsiniz ya da diğer mobil işletim sistemlerinde en temel yazılımlar olarak bilinen arama yapan(dialer) yazılımı ya da mesajlaşma (messaging) yazılımını, masaüstü ortamını tamamen yeniden geliştirebilirsiniz ya da marketten yeni alternatifleriyle değiştirebilirsiniz. Ayrıca Android sistem üzerinde uygulama geliştirmek de çok kolaydır. Sistem uygulamalara, telefonun o anki  konumunu ve diğer bilgileri çok kolay erişilebilir olarak sunar. Çok karmaşık olarak bilinen uygulamaları bile yazmak bazen çok kısa zaman alabilir.
Android geliştirme konusunda varolan türkçe kaynak sıkıntısına birazcık da olsa çözüm oluşturması ve Türkiye’de Android geliştirme konusunda yeni geliştiricilere yardımcı olması için bu blogu oluşturduk. Umarız yararlı bir çalışma olacaktır.
Read More