Android para kazanmak veya kazanamamak

"Olmak ya da olmamak işte bütün mesele bu "
William Shakespeare

Biraz yukarıdaki özdeyiş gibi oldu başlık. Bu sefer konumuz Android marketteki icraatlar olacak. Bir önceki yazımda Android uygulama geliştirirken nasıl para kazanabileceğimizden bahsetmiştim ve son paragrafta sadece para kazanmak için içi boş uygulama yapmak istemediğimi yazmıştım. Bu yazım market/ uygulama/ kazanç performansları hakkında olacaktır.

Mobil uygulamalardan para kazanmak için belirlenen henüz temel üç yol olduğundan bahsetmiştik. Aslında 4.seçenek AppStore'da yerini aldı fakat tüm marketlere gelmediğinden temel olarak kabul etmiyorum.
  1. Uygulama bedava para reklamlardan
  2. Uygulama bedava ekstra özellikler paralı
  3. Uygulama paralı
  4. Uygulamanın başka geliştiricilere transferi
Öncelikle henüz paralı veya uygulama içi satın alma içeren bir uygulama geliştirmiş değilim. İlerleyen zamanlarda inşallah nasip olur da sizinle buradan deneyimlerimi paylaşırım. Temel konumuz hala reklam ile para kazandıran uygulamalar olacak.

Uygulama geliştirirken sırf reklam koyup para kazanayım, indirme başına para kazanıyorsam sadece indirilmesini sağlayayım, uygulamanın kalitesi önemli değil iş görsün reklam gösterip para kazandırsın demek ve bunun gibi sadece paraya odaklanarak uygulama yapmak tamamiyle bize kalmış bir tercihtir. Hele Google Play şartlarında çocuk oyuncağı diyebiliriz. Google Play anlayışı gereği siz hiçbir denetime tabi olmadan uygulamanızı markete yüklersiniz. Uygulama için şikayet gelirse o zaman inceleme başlatılır ve uygunsuz durumlarda uygulamanız marketlerden kaldırılır. Uygunsuz durumlara sayılacak birçok sebep mevcuttur ve Google bunların hepsini tek tek denetler. Bir uygulamanız askıya alınırsa onu askıdan kurtarmanız imkansızdır diyebilirim.


Askıya alınan uygulamalardan kendimden iki örnek verebilirim. Birisi daha ne olduğunu anlamadan google tarafından kapatılan bir uygulamadır ki sadece açıklamasını yanlış yazmıştım, diğeri ise kullanıcı şikayeti ile başlayıp bir inatlaşmanın sonucu olarak askıya alınan uygulamadır. Google Play şartlarını sürekli çiğner veya daha büyük kabahatler işlerseniz bu sefer hesabınız da kapatılır.

Hemen hemen her Android uygulama marketlerinde durum bu şekilde iken IOS uygulama marketi olan AppStore için durum biraz farklıdır. Orada uygulamanız markette yer almadan denetime tabi tutulur ve şu garantiyi vereyim içi boş tekrar uygulamayı kabul ettirmeniz imkansız gibi bir olaydır. "Bu uygulamanın web sitesinden farkı nedir? Fonksiyonelliği yok." diyerek bile kabul etmeyebilirler.

Amacımız başlığımızda belirttiğimiz gibi para kazanmak. İyi de mobil uygulamalardan nasıl para kazanacağız? Uygulama gelirlerimizi nasıl arttıracağız? Uygulama sayısı ile gelirler doğru orantılı artar mı? Çok uygulama çok gelir demek doğru mudur? Henüz bu soruların tamamına yanıtım kesin olmasa da tecrübelere dayanarak sorulara cevap bulmaya çalışacağım.

İyi de mobil uygulamalardan nasıl para kazanacağız?

Arkadaşım bu sorunu bir önceki yazımda kendimce anlattım. Bu kısımda biraz daha derinlere iniyor olacağız. Hala merak ediyorsan seni bir önceki yazıma buradan alabilirim.

Uygulama gelirlerimizi nasıl arttıracağız?

Artık para kazanıyoruz. Kişiye göre kazanç kelimesi anlam olarak yerini buluyorsa (bazıları için 1-2 dolar kazanç iken, bazılarına 1000-2000 dolar kazanç olarak görünmez) en azından aylık ödeme alabiliyorsak yani 100 dolar ve üzeri kazanabiliyorsak ve devam etmek için kararlıysak bu soru bize göre diyebiliriz. 3 ayda 5 dolar kazanarak bu işe başlayan, bu işe kazanç gözüyle bakan biri olarak sizlerle tecrübelerimi paylaşacağım. 

Mobil uygulamalarda reklam kapısından gelir elde ediyorsak amaç tıklanma oranını artırmaktır. Yapabileceğimiz ilk ve en etkili icraat bu olacaktır. Elbette her tık aynı ücreti getirmeyecektir. Yeri gelecek değerli reklamlarda alacağınız bir tık değeri düşük reklamlardan alacağınız 10-20 tıka eşdeğer olacaktır. Reklam çeşidini biz belirleyemediğimiz için (seçtiğimiz uygulama konusuna ve filtrelere göre kısmen belirlemiş olsak da bu güç reklam veren firmanın elindedir)  yapabileceğimiz tek şey tıklama sayısını artırmaya yönelik işlemler ve reklam pazarı bizim ülkemizden daha değerli pazarlar için uygulama geliştirmek olacaktır. Örneğin Amerika'da reklam verenler dolar değeri üzerinden verdiği ve rekabet fazla olduğu için daha değerli reklamlar yayınlanır. Aynı şekilde para değeri Türk Lirasından düşük Ukrayna için yayınlanacak reklamların değeri de düşük olacaktır.

Tıklama sayısını artırmak için reklam yerleşimi tipi ve gösterim sayısını artırmamız gerekecektir. Yapacağımız uygulamada kullanıcının parmaklarının daha çok ziyaret edeceği bölgelere reklam yerleşimi elbette daha akıllıca olacaktır. Bir listenin sonuna reklam yerleşimini koymak Android telefonların tuş takımını düşündüğümüzde mantıklı bir yerleşim yeri olacaktır.

Reklam yerleşimi ile birlikte gösterim sayısı da çok önemlidir. Günde 100 reklam gösteriminde alacağınız tıklama oranı ile 10.000 reklam gösteriminde alacağınız tıklama oranı doğru orantı olmasa bile ne kadar fark eder siz hesaplayın. Aşağıdaki resimde günlük reklam gösterim sayısıyla birlikte tıklamaların artışını rahatlıkla görebiliyoruz.



Reklam gösterim sayısını artırmak için uygulamamızı ya 
çok kullandıracağız ya da birden fazla uygulama ile kullanıcılara hitap etmeye çalışacağız. Uygulama içerisinde daha fazla ekran yaparak, uygulamamıza günlük değişim fonksiyonu katarak (borsa, döviz, haber gibi günlük değişen bilgiler), ya da oyun gibi sürekli açık tutması gerekecek uygulama yaparak kullanımını artırabiliriz. Kullanımı artan uygulamanın reklam gösterimi dolayısıyla reklama tıklatma şansı artar. Bazı uygulamalar gibi bir ekrandan diğer ekrana geçişte reklam çıkarıp tıklanmayı sağlamasını ve bunun gibi ali-cengiz oyunlarını tasvip etmiyorum. Bu tarz hileli durumlara verebilecek çok yaratıcı örnekleri ve bunların güzel paralar getirdiğini görsem de sizlere de önermiyor kendim de kullanmıyorum.

Yukarıda bahsedilen çeşitlemelerle uygulamanın kullanımını dolayısıyla reklam gösterimini artıramıyorsak artık uygulama sayısını artırmak zamanı gelmiştir. İşte bu kısımda sıra diğer sorumuza geliyor.

Uygulama sayısı ile gelirler doğru orantılı artar mı?

Konumuz mobil uygulamalar olunca, biz de üretici konumunda isek uygulama çeşitliliğini artırmak gelirlerimizi artırmak için bir yöntem olabilir. Farklı uygulamalar yaparak reklam ağımızı genişletebilir daha çok kullanıcıya ulaşabilir ve reklam gösterme sayımızı artırabiliriz. Mantıken doğru olan bu seçim, pratik hayatta uygulamanın kullanılmasına bağlı olarak değişeceğini görebilirsiniz.

Örnekten yola çıkarak bir uygulama yaptığımızı 5-10 bin indirme aldığını ve günlük 1-2 binlik reklam gösterimine ulaştığımız düşünelim. İndirme sayısının artmadığını güncellemelerin fayda vermediğini uygulamanın belirli bir reklam gösterim aralığına oturduğunu düşünelim. Böyle bir senaryo için farklı uygulamalarla yolumuzu açmak faydalı olacaktır. Ama kesinlikle bir sonraki uygulamanın da aynı olacağını düşünmeyin.

Kendimden örnek vermek gerekirse ilk 3 ayda 5 dolar para kazandığımı söylemiştim. Bu parayı 2 uygulama ki - bu uygulamalar günlük açılıp bakılması gereken uygulamalardı, üzerinden kazandım. Daha sonra yaptığım 2 uygulama ile sonraki ay 100 dolar kazandım ki  bu uygulamalardan birisi günlük diğeri ise istenilen zamanda kullanabilecek veri içeren uygulama idi. Gördüğünüz gibi uygulama sayısı ile bir artış yakalamış oldum. Hatta aynı uygulamanın diğer ülkeler için farklı versiyonlarını yaparak uygulama sayısını da artırabilirsiniz. Eskiden kabul gören bu teknik artık tek uygulamaya birden fazla dil desteğiyle terk edilmeye başlanmıştır diyebilirim.

İşin güzel tarafı daha önceden gelir getirmeyen ilk iki uygulama sonraki uygulamaların desteğiyle daha güzel indirme sayılarına ulaşmış oldu. Marketlerin güzel bir tarafı da üreticinin diğer uygulamalarından seçmeleri de kullanıcıya göstermesidir. Bu nedenle fazla uygulama yapmanın sadece gelir anlamında değil de popülerlik anlamında katkısı olacağını söyleyebilirim. Yoksa bir uygulama ile milyonlarca dolar kazanan şirketler de var.

Uygulamanın popülerliği, kullanım süresi elinizde değil. Bazı yollarla indirme sayısını artırabilir güzel yorumlar yazdırabilirsiniz. Sonuç olarak bu tarz işlerle belli müddet ilgilenebilecek sonrasında gelecek doğal davranışlarla uygulamanız markette belli bir yerde konumlanacaktır. Bu biraz da şans işi diyebilirim.

Mobil uygulama sayısının ve çeşitliliğinin (kategori çeşitliliği diyebiliriz) kullanıcı sayısını artırdığını gördük. Kullanıcı sayısıyla beraber kullanım oranı dolayısıyla reklam gösterim oranı da arttı. Sıra sayılardaki artışla birlikte gelirlerdeki artışı incelemeye geldi.

Çok uygulama çok gelir demek doğru mudur?

Bir kere konu insan ve tercihleri olunca çeşitliliğin inanılmaz arttığını görebiliyoruz. Çeşitlilik konusunu ev, araba, bilgisayar gibi aklınıza gelebilecek hemen her konuda düşünürseniz ne kadar farklı seçenekler olduğunu görebilirsiniz. 3+1 ev için ne kadar çok çeşit olabileceği, C sınıfı 4 silindirli hatta 1.6 benzinli bir otomobili kaç farklı markada ve şekilde bulabileceğinizi ve insanların bunları nasıl tercih ettiğini düşünün. Dikkat ederseniz temelde ihtiyaçlar belli olsa da, ürünler bu ihtiyaçlara cevap verse de her ürünün bir alıcısı oluyor. Kimi ürünler fazla satıyor kimileri ise istenilen rakama ulaşamıyor. Kimi ürünler de aynı işlevi görmesine rağmen daha kaliteli, daha çekici olabiliyor. Belki A firmasının 100 ürün satışından elde ettiği geliri aynı işlevsel ürünü B firması 1000 satış yaparak elde ediyor. Bu noktada kalite, tasarım, marka, hizmet gibi ince detaylar işin içine giriyor.

Mobil dünyada da bu durum böyle. Bir araştırmaya göre marketlerde bulunan uygulamalardan %60'ı indirme almamış. Bugünlerde bir milyar uygulamadan bahsedilen bir market için %60 çok ciddi bir rakam. Bu rakamın sadece market için değil aynı zamanda üreticiler için de düşündürücü olması gerekir. Nasıl bir üretim ve çeşitlilik ki 1 milyar civarında uygulama var ve bunlardan 600 bin civarında uygulama tercih edilmiyor. Tercih edilmeyen bu uygulamalar yeri geliyor bir market temizliğine kurban da gidebiliyor. Elbette hepimiz uygulamamızın tercih edilen hatta en üst sıralarda yer alan uygulama olmasını dileriz.


Sadece sayıları (indirme, gösterim) artırmak amaçlı hazırladığımız uygulamalar kimi zaman istediğimiz gelir performansını elde edemiyor. Kendimden olarak örnek verecek olursam, son zamanlarda sadece sayı artırmak için hazırladığım basit bir kaç uygulamanın gelir performansını sizlerle paylaşabilirim.

Gördüğünüz gibi pazar araştırması yapmadan (bu uygulamaların muadilleri fazlasıyla var), gerekli özeni göstermeden (muadil varsa daha farklı, kapsamlı yenilikler içerebilir) hazırlayacağınız uygulamalar gelir anlamında beklediğinizi size veremeyebilir. Hatta o kadar kötü ki son uygulamadan 3 gündür haber bile alınamıyor (3 gündür uygulama kullanılmıyor). Kısacası çok uygulama çok gelir demek değildir. 

Sonuç olarak mobil uygulamalardan reklam yoluyla para kazanmak için analiz çalışmaları yapmalı nereye reklam yerleştirip, nasıl uygulamalar üretip, hangi kategoriler altında yer alacağımızı iyi seçmeliyiz. Kimse aklındaki uygulama yapılmış diye uygulama geliştirmeyi bırakmasın. Unutmayın ki Google piyasaya çıktığında yahoo, altavista gibi onun üzerinde arama motoru vardı.

Uygulama dünyasından herkese bir arazi düşürmesi, bu arazinin ilerde değerlenmesi dileğiyle...






Nesneye Dayalı Programlama (OOP) S.O.L.I.D ilkeleri

Bu aralar işlerden fırsat bulup araştırmalar yapıyorum. Belli bir konu üzerinde araştırma yaparken özellikle araştırmayı internet üzerinden yapıyorsanız dallandıkça dallanıyorsunuz. Konu ile ilgili bir makale okurken, makale içinde geçen bir bağlantıya tıklayarak veya makale içinde geçen bir kısalmanın anlamını arayarak ana konudan diğer konulara geçiş yapıyorsunuz.

Son zamanlarda tasarım kalıpları (desing patterns) üzerinde çalışmaktayım. Benim gibi sürekli pratik ile ilerleyen birisi için, kitab-i bilgilere girmek devrim sayılabilir. Tasarım kalıpları kısaca herhangi bir programlama dilinden bağımsız, bir uygulama tasarımında hangi yolların izlenebileceğini, yaparken nelere dikkat edilmesi gerekebileceğinden bahseden konular bütünüdür. (Çok ilginç bir tanım oldu inşallah doğrudur) Özellikle belli başlı tasarım kalıplarını incelerken S.O.L.I.D ilkeler adlı bir konuya daha doğrusu kısaltmaya denk geldim ve dallanarak SOLID 'in ne olduğunu araştırdım.

"SOLID Principles" (katı ilkeler) olarak geçen bu konu aldığı isim ve anlattığı konunun uyuşmasıyla muhteşem olmuş diyebilirim. Nedir bu S.O.L.I.D ilkeler? Nerede kullanılır? Nasıl yapılır?

Aslında kurumsal uygulama geliştiren, uygulama geliştirirken biraz nesneye dayalı programlama tekniklerini kullanmaya çalışan her yazılım geliştiricinin haberi olarak ve/veya olmadan uyguladığı bazı tekniklerdir. SOLID ilkeleri aşağıdaki gibi açıklayabiliriz.
  • Single Responsibility Principle (Tek sorumluluk)
  • Open / Close Principle (Açık / Kapalı olma durumu)
  • Liskov Substitution Principle
  • Interface Segregation Principle (Arayüz Ayırma)
  • Dependency Inversion Principle (Bağımlılıktan kurtarma)
Single Responsibility Principle (SRP) : Her sınıf tek bir amaca hizmet etmelidir. Genel kural olarak yazılan her bir sınıfın sadece yazıldığı amaca hizmet etmesi diğer sınıfların işlerine veya kendi işlemlerinin dışında bir işlemi gerçekleştirmemesi istenir. Basit bir örnekle dört işlem adında bir sınıf hazırlıyorsanız, içerisinde dört işlemi yapan fonksiyon, değişken tanımlamanız gerekir. Kök alma, faktöriyel, kombinasyon, permutasyon... gibi işlemler de dört işlemle yapılıyor diye aynı sınıfın içerisine yazmamanız gerekir. Sınıf adına uygun şekilde işini gerçekleştirmelidir. Aşağıdaki gibi bir örnek de verebiliriz.


Dikdortgen sınıfına ait AlanHesapla ve CevreHesapla sınıfın kendi işlevidir. CizimYap fonksiyonu ve fonksiyona ait değişkenler her ne kadar Dikdortgen sınıfına hizmet ediyor gibi görünse de aslında genel bir çizim fonksiyonu olabilir ve ikinci kısımda belirtildiği şekilde ayrı bir sınıfta değerlendirilmelidir.

Open / Close Principle (OCP): Yazılım içerisinde kullanılan varlıklar (sınıf, fonksiyon, modül gibi) değime kapalı, genişletmeye açık tutulmalıdır. Yani her fonksiyonel değişimde uygulamanın varlıkları değişime özel değişmemeli aksine ek özellik olarak genişletilebilmelidir. Konu nesneye dayalı geliştirme olunca miras özelliğinden faydalanarak absract, virtual, protected sınıflar, fonksiyonlar, değişkenlerin kullanımı yapılması gerekir. Örnek olarak aynı sınıfları kullanacak farklı projeler için, sınıflar her projeye özel değiştirilmemeli, aksine her projede miras alınarak yapabilecekleri genişletilmelidir.


Liskov Substitution Principle (LSP):
İngilizce açıklamalarında anlaşılması zor bir ilkedir. Genel olarak türetilen bir sınıfta, ana sınıfın fonksiyonlarını kullanırken beklenti ve sonuç ilişkisinin doğru kurulması istenir. Türetilecek sınıf için fonksiyonların nasıl sonuçlar çıkaracağını ve ne çıkarması gerektiğini önceden detaylı düşünülmesi gerektiğini belirtir. Popüler örnekle açıklayacak olursak;


Kare sınıfı aslında bir dikdörtgendir. Dolayısıyla kare sınıfı dikdörtgen sınıfından türetilebilir. Yukarıda yazılan kod doğru gibi görünse de test kodunda beklenen sonuç ile gerçek sonuç farklılık göstermektedir. Bu hata Kare sınıfının Dikdörtgen sınıfından en azından bu şekilde türetilemeyeceğini gösterir ve bu türemenin yapılabilmesi için daha fazla düşünmenin gerekliliği ortaya çıkar.

Interface Segregation Priciple (ISP): Nesneye dayalı programlamada kullanılması gereken arayüzlerin (Interface - grafik arayüz "GUI" değil) içerdiği metotlarda gereksiz yoğunluğun azaltılması istenir. Arayüzü kullanacak programcıların, kullanmayacakları metotlara zorlanması istenmez. Bu sebeple üretilen arayüzlerin küçük kapsamlı olması ve nokta atışlı fonksiyonlar içermesi istenir.

Örneğin DB adlı arayüz veritabanı işlemleri için oluşturulmuşsa, "SelectByName" ve "UpdateByName" fonksiyonları zorunlu olmamalıdır. Çünkü bu fonksiyonlar "Name" kolonu içeren fonksiyonlar için çalıştırılmalı, kolonu içermeyen tablolar için veya içermese de başka bir fonksiyonu gerçekleştirmek için kullanılmamalıdır. arayüz programcıyı sadece her sınıf için gerekecek fonksiyonların oluşturulmasına zorlamalıdır.

Dependency Inversion Principle (DIP): Aslında çıkış noktam bu konuydu. Dependency injection ve Inversion of control konularını incelerken karşıma SOLID yapısı çıktı. Bu ilke yüksek seviyedeki modüllerin, düşük seviyedeki modüllere bağımlı olmaması gerekliliğini belirtir. Bağımlılık sadece soyutlamalar (abstractions) üzerinden yapılmalıdır. Ayrıca bu bağımlılıklar detay içermemeli, aynı şekilde soyut kavramlara bağlanmalıdır. Tanım bu şekilde ama sanki biraz soyut kalıyor. Örneğe geçecek olursak;

Personel sınıfı için kaydetme fonksiyonu oluşturmak istediğimizde (Personel üst sınıf) kaydetme şeklinin uygulama içerisinde üç farklı seçenekle yapıldığını düşünelim. Çalışma anında kaydetme şekli belirlenecek ve personel o şekilde kaydedilecekse yazdığımız sınıftaki gibi bir çözüm üretebiliriz. Fakat bu sınıfta SOLID ilkelerinin birincisi olan sınıfa ait tek sorumluluk ilkesi çiğnenmiş oldu. Çünkü Personel sınıfı içerisine dosyaya, log'a ve veri tabanına yazma fonksiyonlarını getirdik. Ayrıca kaydetme fonksiyonu da gereksiz olarak büyüdü.

Sonuç olarak Personel sınıfı hem tek sorumluluğu içermedi hem de kaydetme fonksiyonlarına bağımlı bir yapıya büründü. İleride yeni bir kaydetme türü için Personel sınıfı içerisine yeni bir fonksiyon eklenmeli ve mevcut (Save) fonksiyonda değişiklik yapılmalıdır. Değişiklik yaparak ikinci ilke "Açık / Kapalı durumu" (OCP) çiğnenmiş olur.

Çözüm olarak farklı bir tasarıma gitmemiz gerekir. Personel sınıfı kaydetme fonksiyonunu içermeli, nasıl kaydedeceğini bilmemelidir. Ayrıca kaydetme seçenekleri yeni sınıflar sayesinde arttırılabilmeli ve bundan Personel (üst sınıf) haberi olmamalıdır.
Örnekte Personel sınıfının kaydet metodu bir arayüz (soyut) kullanarak kaydetme işlemini gerçekleştirir. Nasıl gerçekleştireceğinden haberi yoktur. İşlemi "Saving" adlı arayüz (interface) üzerinden gerçekleştirir. Bu sayede SOLID için birinci ilke (SRP) tamamlanmış olur. Üç farklı kaydetme işlemi için, üç farklı sınıf oluşturulmuştur. Bu sayede çalışma anında seçilecek tür ile kaydetme fonksiyonu gerçekleştirilir.

Artık Personel sınıfı tek sorumluluk taşıyan ve bağımlılıkları ortadan kalkmış bir sınıftır.



Android ile Sosyal Medya Paylaşımı

Günümüzde sosyal medyanın popülerliği tartışılamaz. Dolayısıyla bir yazılım geliştirici olarak uzak kalamıyoruz. Aslında hazırlayacağımız uygulamalar için sosyal medyayı reklam açısından faydalı buluyorum. Bir kişinin arkadaş listesinde ortalama 250 civarı kişi olduğunu düşünürsek, bu kişinin hazırladığımız uygulama ile birşey paylaşması web uygulamaları için URL bilgisinin, mobil uygulamalar için uygulama isminin anında 250 kişi tarafından görülmesi demek oluyor. Tabi beğenen kişilerin zincirleme reaksiyon olarak paylaşıma devam etmeleri sonucu hazırladığınız uygulamanın tanıtıma ne denli etki yaptığını düşünebilirsiniz.

Hal böyle olunca bir kaç android uygulamaya paylaşım fonksiyonu eklemek için kolları sıvadım. Kolları sıvadım ama işler o kadar basitleşmiş ki sadece Android Intent ekleyerek paylaşımı gerçekleştiriyormuşuz. Aşağıda kodu hemen paylaşayım;

Intent sendIntent = new Intent(); sendIntent.setAction(Intent.ACTION_SEND); sendIntent.setType("text/plain"); // text/html sendIntent.putExtra(Intent.EXTRA_TEXT, ResultStr); startActivity(Intent.createChooser(sendIntent, "Share"));

Gördüğünüz gibi paylaşmak istediğiniz şeyi (bu örnekte yazıyı) 5 satır kod ile gerçekleştirebilirsiniz. ACTION_SEND işleminde oluşturacağımız bir Android Intent 'ine EXTRA_TEXT parametresi olarak paylaşmak istediğimiz yazıyı gönderdikten sonra aktivite olarak başlattığımızda paylaşım kanalı olarak tek bir kanal varsa onun üzerinden paylaşma gerçekleşir. Paylaşım tipinde yazı değil resim video kullanmak isterseniz setType("text/plain") fonksiyonunda değişiklik yapmanız gerekecektir. Bu alana MIME type (text/plain, text/html, image/bmp, image/png, video/mpeg, video/avi ...) bilgileri girilir.

Dikkat ederseniz paylaşım için kullanılacak kanal (Mesaj, facebook, linked-in, whatsapp....) belirtilmesi yapmadım. Bunun sebebi paylaşım kanalını kullanıcının belirliyor olmasıdır. İşletim sistemine yüklü olan uygulamalar işletim sisteminin sağladığı paylaşım kanalını kullanabilmeleri için kendilerini kayıt (register) ettirmeleri gerekir. Yani siz telefonunuza veya tabletinize Whatsapp ya da Facebook yüklediğinizde bu uygulamalar paylaşma özelliği için kendilerini işletim sisteminin sunduğu paylaşım kısmına kayıt ederler.

Bir geliştirici olarak paylaşım özelliğini kullanırken yukarıdaki kod dışında bir kod yazmamız gerekmez. Eğer birden fazla paylaşım kanalı varsa kullanıcı paylaşım yapmak istediğinde soldaki örnekte olduğu gibi (yüklü uygulamalara göre seçenekler değişebilir) bir liste ekrana çıkacaktır. Kullanıcının seçtiği paylaşım kanalına göre gönderilecek parametre kullanılan uygulamanın formatına göre şekil alacaktır.

Bu kısımda Facebook' a özgü bir hatadan (bug) bahsetmek isterim. İçinde URL olmayan bir text mesajı paylaşmak istediğinizde facebook seçiminden sonra gelen Facebook paylaşım ekranını boş göreceksiniz. Bu Facebook uygulamasının paylaşımda URL kullanmasından kaynaklanmaktadır. Henüz bir çözümüne rastlamadım. Çözüm üretenler burada çözümü yazarlarsa sevinirim.

Facebook dışında denediğim her uygulama (Gmail, Mesaj, Linkedin, WhatsApp) için olumlu sonuç aldım.

C# - Nibernate Mapping (Nesne Haritalama)

Yeni bir projeye başladığımı daha önceki Android yazımda belirtmiştim. Projenin iki ayağından sunucu için olan kısımı .NET web uygulaması olarak yapmaya çalışıyorum. Benim gibi datatable, datarow, sql string kullanmayı alışkanlık haline getirmiş birisi için yeni sayılabilecek MVC ve ORM (Object Relational Mapping) kavramlarını kullanmayı  planladım. Bu bağlamda projeye asp.net MVC3 ile NHibernate kullanarak başladım.

Öncelikli olarak şunu belirtmek isterim ki, kendi adınıza veya küçük ölçekli bir işletme için geliştireceğiniz uygulamalarda bağımlı olduğunuz geliştirici sayısı üç-beş kişiyi geçmiyor, yazacağınız uygulama eklentilerle ve kullanım oranıyla hayal edemeyeceğiniz büyüklüklere ulaşmayacak ise dilediğiniz şekilde kodlayabilirsiniz.

Ama uygulamada geliştirici sayısı artacak, uygulama eklentilerle ve uygulama alanı ile genişleyecekse nesneye dayalı uygulama geliştirme ve onun getirisi olan patternleri ve araçları kullanmak gerekiyor. ORM kavramı da ilk olarak bu kısımda devreye giriyor.

.NET MVC ile uygulama geliştirmeye başlayınca view, controller ile veri katmanını oluşturacak model kavramına giriş yapıyorsunuz. Ben NHibernate kullanmayı tercih ettim. Siz FluentNHibernate, Entity Framework gibi başka ORM araçlarını kullanabilirsiniz.

Bu açıklamalar ne kadar uzarsa uzasın örnek olmadan, kod görmeden kolay anlamayan biri olarak sizi de daha fazla sıkmadan örneğe geçelim. Örnek olarak bir kategori, ürün, sipariş üçlemesinden oluşan veritabanı üzerinden yola çıkalım.


 Veri tabanında tabloları oluşturduktan sonra genel görünüm soldaki şekilde olacaktır.Tabloları oluşturduktan sonra uygulama tarafında tabloları işaret edecek sınıfları proje içerisinde oluşturarak sağdaki resmi elde etmiş olacağız. Uygulama tarafında sınıf şemasını oluşturduktan sonra aşağıdaki gibi bir görüntü elde edeceğiz.
Sınıf şemasını incelediğimizde tüm sınıflarda ortak özellik olarak "ID" üyesini (kolonunu) görmekteyiz. NHibernate ile çalışırken her tabloya ait birincil anahtarı kesin olarak belirlememiz gerekir. Bu uygulamada ise tüm sınıflar için otomatik sayı (int / identity) türünden üyeyi anahtar olarak belirlemiş oldum.

Veri tabanı -> Nesne eşlemesinde veri tabanı üzerinde bulunan her kolonu tablo sınıfı üzerinde bir üyeye denk getirmekteyiz.

Sınıf tarafından bakıldığında veri tabanı kolonundan ve yapısından farklı üyelerin (Örn; Product->Category) de sınıf içerisinde yer aldığını görebiliriz.

Hazırladığımız sınıfları nesne yönelimli programlamaya (OOP) daha uygun hale getirmek için ortak üyeleri bir sınıf altında toplayıp diğer sınıflarda bu ana sınıfı miras almamız gerekir. Bu sayede kod yazımı ve kontrolü daha kolay sağlanmış olur. En azından bundan sonra üreteceğiniz diğer sınıflar için "ID" kolonunu yazmak zorunda kalmazsınız. Sınıfları "_Base" ve "_BaseCaption" adlı iki sınıftan türettikten sonra aşağıdaki şemayı elde etmiş oluruz.


Veri tabanı, tablolar ve sınıfları oluşturduktan sonra asıl konumuz olan eşleşmeyi sağlayacak ilişkileri belirlemeye geldi. NHibernate kullandığınızda bu ilişkileri XML dosyasında oluşturmanız gerekecektir. Aynı şekilde FluentNhibernate kullansaydık .cs uzantılı dosyada kodlama yaparak veri tabanı haritalamasını gerçekleştirmiş olacaktık.

Projenize düzen hakim olması açısından sınıflarınızı ve harita dosyalarınızı ayrı bir klasörde tutmanızı öneririm. Hatta her sınıf için ayrı bir .cs ve .xml dosyası projenin anlaşılması bakımından oldukça faydalı olacaktır. En üst proje resminde haritalar için ayırdığım "Map" klasörü görünmektedir.

Her sınıf için teker teker eşleşme dosyalarını oluşturduk. Dikkat ederseniz dosyaların ismi sınıf isminden sonra ".hbm" takısı alıyor. Uygulama çalıştıktan sonra NHibernate eşleşme dosyalarını bu uzantıyı kullanarak arıyor ve bulduktan sonra eşleşmeyi gerçekleştiriyor.

Burada önemli olan bir konu da bu eşleşme dosyalarının assembly içerisine yerleşmesidir. Her harita dosyasının üzerine sağ tıkladıktan sonra özelliklerden "Build Action" özelliğini "Embedded Resource" yaparak hazırladığımız dosyaların derleme sonucu oluşacak DLL içerisine yerleşmesini sağlayabiliriz.

Harita dosyalarının içerisine gelecek olursak, sizlere iki farklı örnek üzerinde detayları verebilirim. Sipariş ürünleri (OrderProduct) tablosundan gidecek olursak resimde xml içeriği, sınıf şeması, tablosu ve sınıf kodu aşağıdaki şekilde olacaktır.


Görüldüğü gibi xml içerisindeki ikinci satırda NHibernate için haritalama kuralı yazılmaktadır. Burada dikkat edilecek kısım kırmızı çizgi ile belirtilmektedir. Oluşturacağımız namespace ve assembly bu kısımda mutlaka belirtilmelidir.

Tablo ismi ve sınıf ismi belirtildikten sonra "ID" kolonunun belirtilmesi gerekir. Burada birincil anahtar "ID" kolon değerinin otomatik olacağı "<generator class="native"/>" ibaresiyle belirtilmektedir.

Birincil anahtar sonrasında her bir üye tek tek "property" olarak tanımlanır. Üyelerin tanımının peşine gelen satırlarda ilişki tanımı yer alıyor. Tablomuzda bulunmayan fakat sınıfımızda tanımladığımız nesneleri burada ilişkili hale getiriyoruz.

Üyeleri (kolon bazında) tanımladıktan sonra sınıf içerisinde belirlediğimiz ilişkili üyeleri tanımlamamız gerekir. Bu kısımda "many-to-one , one-to-one" ilişkilerini tanımlayabilirsiniz. İlişki tanımlamada "name, class, column" üçlüsü yani yukarı mavi renklerle belirttiğim kısımlara dikkat etmemiz gerekir. Aynı veri tabanı tablolarında olduğu gibi ilişkinin artması performansı çekilecek sorgunun büyüklüğünü etkilediği gibi nesne sınıflarında ilişki tanımının artması da aynı etkileri yapar.

Performans açısından ilk dikkat etmemiz gereken kısım ilişkilerin nesne yaratıldığında yüklenip yüklenmemesini "lazy" özelliği belirlemektir. Üç tip olarak nesne yüklemesini aşağıdaki gibi yapabiliriz.

  • Nesne yüklendiğinde ilişkili tablodaki veri de yüklensin lazy="false"
  • Sadece nesne yüklensin ilişkili tablodaki veri kullanmak istediğim zaman yüklensin lazy="proxy"
  • Sadece nesne yüklensin ilişkiyi gösteren nesne bile yüklenmesin lazy="no-proxy"

Veri tabanında ilişkili tabloların ilişkileri üzerinden birbirlerini etkilmesi "cascade" olayı da haritalamada tanımlanmalıdır. Eğer nesnelerin "insert, update, delete" işlemlerinde ilişkili tabloyu etkilemesini istiyorsanız cascade özelliğine ilgili değeri belirlemeniz gerekir. Oluşturma, silme, güncelleme işleminde ilişkili tablo önemli değilse benim gibi cascade="none" kullanabilirsiniz.


İkinci örneğimizde ilk örnekten farklı olarak "bag" kavramına değinmek isterim. Bir kaydın diğer bir tabloda birden fazla alt kayıt içermesi durumunda liste tipi verileri kullanmamız gerekecektir. NHibernate ile üç liste  tipi kullanabiliriz.

  • "Bag" sırasız liste tipidir. Çift kayıtları (duplicate) içerebilir. .NET karşılığı olarak IList kullanılır.
  • "List" sıralı liste tipidir. Çift kayıtlara (duplicate) izin verilir. İndeks (Index) kolonunun belirtilmesi gerekir..NET karşılığı olarak IList kullanılır.
  • "Set" sırasız liste tipidir. Çift kayıtlara izin verilmez. Her kayıt eşsiz (unique) olmalıdır.
Yukarıdaki örnekte ilişkili alt verileri liste şeklinde elde etmek için "Bag" özelliğini kullandım. Bu özelliği kullanırken anahtar kolonu ve ilişki tipini de belirlemek gerekir. Anahtar (<key/>) kolon, ilişkili tablo üzerindeki kolondur. Ana tablo üzerinde varsayılan olarak id yani ID kolonu ilişkiyi belirler. Biraz karışık olduysa örnek üzerinden açıklayalım.


Ana Tablo
İd
İlişki Tablosu
Anahtar
Product
ID
OrderProduct
ProductID
Order
ID
OrderProduct
OrderID


İlişkiyi belirlemede id kolonunu kullanmak istemiyorsanız, ana tablo üzerinde ilişkiyi belirleyen farklı bir kolon varsa "bag" özelliğinde bunu da belirtebiliriz.

      <!--property-ref ana tablodaki, column ise diger tablo -->
      <key column="OrderID" property-ref="xID"></key>

Bu yazımızda Nhibernate ile kısaca temel tanımlamalara değinmiş olduk. Temel diyorum çünkü  NHibernate kullanmaya başladığınız zaman kullanacağınız parametrelerin bu kısa yazıya sığmayacak kadar çok olduğunu görünce hak vereceksiniz.

Android Asenkron Resim Gösterimi (URL - Web'den)

Şu sıralar yeni bir Android projesi ile uğraşmaktayım. Bu seferki projem diğerlerinden farklı olarak bana ait markete koymak için yaptığım bir proje değil. Projenin detaylarına girmeden kısaca başımdan geçen bir olayı sizinle paylaşmak istedim.

Projenin bir menüsünde sunucudan alınan veriler üzerinden yine sunucuda bulunan resimlerin gösterilmesi gerekiyordu. Basitçe “Android ile url (web) kullanarak nasıl resim gösteririm?” sorusunun cevabını araştırmam gerekiyordu.

Dilerseniz ufak bir kod parçasıyla bunu nasıl yaptığımı size özetleyebilirim.

public static Drawable LoadImageFromWebOperations(String url) { try { InputStream is = (InputStream) new URL(url).getContent(); return Drawable.createFromStream(is, "name"); } catch (Exception e) { Log.e("LoadImage", "exception", e); return img.getResources().getDrawable(R.drawable.noimage); } }

Yukarıdaki fonksiyonu statik olarak tanımlarsanız sadece parametre göndererek url'den resminizi elde etmiş olacaksınız.

Bir fonksiyon ile URL’den resim dönüşümü yaptıktan sonra işlerin kolaylaştığını düşünerek uygulamayı çalıştırdım. Uygulama içerisinden resim gösterme kısmına geldiğimde ise hata aldım.

"android.os.NetworkOnMainThreadException"

Hata için önce yazdığım koddan şüphelenip değişik kodlamalar denedikten sonra cevap bulamayınca Google araştırmalarına başladım.  Hatanın tanımı geniş kapsamlı olsa da çözüm sürecinde çoğunlukla “AsyncTask” sınıfıyla karşılaştım. Uygulamamda ilgili ekran için bilgiler bir Thread aracılığıyla Web servis üzerinden alınıyor ve gelen bilgiler ile resimlerin aynı zamanda web’den çekilmesi gerekiyordu. İki network (internet-ağ) işleminin aynı Thread üzerinde aynı anda başlaması sorunun kendisi oluyormuş. Dolayısıyla çözüm için değişiklik şart oldu ve “AsyncTask” sınıfını kullanma gerekliliği ortaya çıktı.

public class LoadImage extends AsyncTask<ImageView, Void, Drawable> { ImageView img; public Drawable LoadImageFromWebOperations(String url) {
try { InputStream is = (InputStream) new URL(url).getContent(); return Drawable.createFromStream(is, "isim"); } catch (Exception e) { Log.e("LoadImageFromWeb", "Hata", e); return img.getResources().getDrawable(R.drawable.noimage); } } @Override protected Drawable doInBackground(ImageView... params) { img = params[0]; return LoadImageFromWebOperations(img.getTag().toString()); } @Override protected void onPostExecute(Drawable result) { img.setImageDrawable(result); }

Async sınıfını kullanarak Thread ile web servis üzerinden aldığım veriyi asenkron iletişime dahil ederek resimlerin gelmesini sağladım. Bu sayede aynı Thread üzerinde web servis ve resim download işleminden vazgeçtim. Yalnız net olmasa da bu hatanın Android 4.0.3 (Ice Cream Sandwich) versiyonundan düşük versiyonlar için kaynaklandığına bir yerde rastladım. Uygulamayı genele yaymak için düşük versiyonlar şart olduğundan çözümü asenkron hale dönüştürmek zorunda kaldım.

Aslında çok basit bir şekilde Thread işleminden vazgeçerek en üstte belirtiğim statik fonksiyonu kullanabilirdim. Fakat uygulama geliştirirken bazen basitlikten çıkmak gerekiyor. Uygulama ekranında Thread kullanmadan yaptığımızda verinin gelme zamanına bağlı olarak ekran donup kalıyor ve kullanıcıya bu durumu izah edemiyorsunuz. Verinin gelmesi ve ekranın düzenlenmesi sırasında Progress Dialog (Yükleniyor ekranı) çıkartarak kullanıcıyı veri hakkında haberdar edebiliyorsunuz. Son olarak thread ile progress dialog nasıl çıkarılır? Yükleniyor (Loading) ekranı ile kullanıcı nasıl haberdar edilir? diye düşünüyorsanız aşağıdaki fonksiyon yardımcınız olur umarım.

Handler mHandler = new Handler(); private void threadprogressdialogyukleme() { // Bu işlemin activity icinde oldugu dusunuluyor // this = Activity final ProgressDialog dialog = ProgressDialog.show(this, "", "Yükleniyor..."); new Thread(new Runnable() { public void run() { get();//Datanın cekildigi yer mHandler.post(new Runnable() { public void run() { // Data çekildikten sonra bu kısımda // gerekli arayüz düzenlemesi yapılabilir. dialog.dismiss(); //Yukleniyor ekranı kapatılır. } }); } }).start(); }

Android uygulama geliştirirken para kazanmak


Hakkında kısmında belirttiğim gibi 2012 yılından beri Android ile uygulama geliştiriyorum.  Hem öğrenme amaçlı hem de bir şeyler yapabilme adına başladığım işten para kazanmanın yollarını keşfettiğimde çok hoşuma gitmişti. Kazanılan paranın büyüklüğü kişiden kişiye fark etse de öyle hayallerdeki gibi büyük meblağlar (tabi bana göre) kazanmayı henüz başaramadım ama uygulama dünyasında kazanamayacağınız anlamına gelmez.  Yine yazılımcı olan bir arkadaşımın sürekli ağzında dolanan artık sloganımız olmuş bir sözü sizinle paylaşmak isterim.

“Bir uygulama bir dolar bir milyon indirme olay bitmiştir”

Gerçekten kabaca bir hesap yaptığımızda 1 milyon dolarlık kazanç bir kişi için 20 yıllık maaşının karşılığıdır. Günümüzde 4bin liralık maaşı (yoksulluk sınırı kabul edilen miktardan fazla) güzel bir maaş olarak kabul edersek basit bir matematiksel hesapla;

(2013) Dolar=1.85 TL Yoksulluk sınırı=3200 TL Google ya da Apple payı: %30

20 senelik maaş geliri
Bir uygulama bir dolar bir milyon indirme
4.000x12x20 = 960.000 TL
1.000.000x1.85x0.70 = 1.295.000 TL

Gördüğünüz gibi sloganın gerçekleşmesi durumunda 20 senelik maaş artı emeklilik primi bir anda elinizde olabilir. Tabi bu iş sloganı üretmek kadar kolay değil. Öncelikle 1milyon kişinin beğenisini kazanacak bir uygulamayı ortaya koyup bir de bunu paralı satabilmek kısmını atlamamak gerekiyor.

Yüksek gelir getiren uygulamalara baktığımızda güçlü firmaların yapımlarının büyük pay aldığını görüyoruz. (Appannie indekslerinden yola çıkarak sizde buradan inceleyebilirsiniz.) Güçlü firmalar çok para, çok çalışan ve büyük projeler demek oluyor. Çok para yatırıp çok kazanmayı bekliyorlar ve beklerken de kendilerini finanse edebiliyorlar.

Uygulamadan çok para kazanmak için illa büyük firma güçlü bir finans şart değil. Kimsenin düşünmediğini düşünmek, basit bir uygulama ile milyonlarca insanın beğenisini kazanmak için kimse sizi engelleyemez. 17 yaşında birinin bir anda milyoner olması uygulama dünyasında şaşılacak bir olay değildir. Önemli olan fikir ve yılmadan çalışmaktır.

Dikkat ederseniz yukarıda anlattıklarım sadece android platformuna özgü bir olay değildir. Aynı şekilde hatta biraz daha iyi pazar payı ile IOS, yeni gelişmekte olan WP-8 platformları da mobil uygulama pazarına dahildir. Benim çalıştığım konu Android platformu olduğundan yazımıza bu şekilde başlamış bulunduk.

Genel perspektifi sloganımız çerçevesinde çizdikten sonra bana ya da sloganı paylaştığım arkadaşlarıma gelecek olursak henüz milyoner olmuş değiliz. Ufukta da öyle milyonları getirecek bir yapım görünmüyor. Peki ,uğraştığımız emek verdiğimiz uygulamalardan nasıl para kazanabiliriz?

  • Uygulamayı paralı olarak kullanıcılara sunarak (Paid)
  • Uygulamayı ücretsiz (bedava, beleş), gelişmiş halini ya da geliştirme eklentilerini paralı sunarak (In-app billing, freemium)
  • Uygulamayı ücretsiz (bedava, beleş) fakat reklam içerikli sunarak (Free with ads)


İlk iki seçeneği henüz demediğim için bu yazımda sizlere 3. Seçeneği anlatmaya çalışacağım. Ücretsiz uygulamaların yüksek çoğunluğu, bazılarının hayrına yaptığı uygulamaların dışında reklamlardan gelir elde eder. Reklamdan gelir elde edebilmek için hitap ettiğiniz kitle ya da siz büyük değilseniz reklam firmalarıyla çalışmanız gerekir. Büyüklük kastım aynı web sayfalarında olduğu gibi yüksek hit oranına sahip değilseniz ya da fatura kesemiyorsanız direkt olarak reklamı siz alamazsınız. Reklamı biz alamıyorsak hangi reklam firmaları ile çalışmamız gerekir?

Mobil uygulama dünyasında birçok reklam şirketi bulunmaktadır. Bunların arasında Türk şirketleri de bulunmaktadır. Ama en popülerlerine bakacak olursak;


Şeklinde özetleyebilirim. (Bazı arkadaşlar bunlara ek olarak birkaç firma daha sayabilir tabi)
Bu reklam şirketlerinden en popüleri bildiğim kadarıyla Admob (yani Google).  Ben de uygulamalarımda Admob reklamlarını kullanmaktayım.

Yukarıda bahsettiğim farklı reklam şirketleri aynı zamanda farklı reklam şekilleriyle de birbirinden ayrılır. Örneğin: Admob standart bir reklam banner’ ı üzerinden reklamcılık yaparken, Airpush ile popup çıkartabilir, StartApp ile indirmeden para kazanabilirsiniz. Tabi hepsinin daha başka ve birbirinin aynı reklam ürünleri de olabilir. (yani Airpush veya Leadbolt ile de banner reklamcılığı da yapabilirsiniz) Konu benim uygulamalarım üzerinden devam edeceği için Admob bu yazıda ağırlık kazanacak.

Uygulamadan para kazanma serüvenim biraz hazin biraz da ağır başladı. İlk yaptığım uygulama daha doğrusu yazılımcı olmayan arkadaşımın yaptığı ilk uygulamayı devşirerek daha gelişmiş bir hal kazandırdıktan sonra Admob reklamlarının uygulama içerisinde yer almasını sağladık.

Admob, Adsense gibi bazı kriterleri sağladıktan sonra kabul edilebileceğiniz bir reklam ağı değildir. Sitesi üzerinden kayıt olup hemen başlayabileceğiniz, geliştirme kitini (SDK) indirdikten sonra uygulamaya ekleyip hemen reklam yayınlayabileceğiniz oldukça basit bir reklam ağıdır.

Arkadaşım sağolsun benim yerime J kaydolup, geliştirme kitini indirdikten sonra uygulama içerisini yerleştirdiğimiz banner ile reklamdan gelir elde etmeye başladık. Hem de ne gelir düşündüğünüz gibi değil J Başlangıçta dediğim gibi uygulamanın indirme ve kullanılma sayısı çok önemli. Dilerseniz size direk rakamları vererek olayı özetleyeyim.

İlk 15 günde 1.33$ yani aşağı yukarı 2 TL J Bu hesapla ayda 4TL olan kazancımız için ödeme almamız (Admob 100$ sonrası ödeme yapar) 40 aydan fazla alacaktı J Bir anda gelirleri artırıp milyoner olamadık. Tabi bu benim yaşadığım örnek, internette daha fazla araştırdığınızda ilk ayda binler kazanan uygulamalar yok değil.

Yılmadan çalışmaya devam ettik. Daha güzel bir arayüz, hadi bir de İngilizcesini deneyelim derken iki ay sonunda 4 küsür dolar ile müthiş bir gelir elde ettik. Bu noktada bir mola verip düşünmeye başladım. Nasıl bir uygulama yapmam gerekir ki reklamdan daha fazla para getirsin. Uzun market (Google play) araştırmaları sonucunda karar verip illeryollar uygulamasını hayata geçirdim. Bu noktadan sonra indirme sayılarının ve kullanımın artmasına bağlı olarak gelirler de artmaya başladı. Artık ödeme alabilecektim J

Sonrasında diğer uygulamalar gelmeye başladı ve ilk hedefim olan aylık ödeme yani ayda 100$ sınırını yakalamaya başladım. Sonrasında koyduğum günde 5$ hedefine ulaşmam bayağı uzun bir zaman aldı. Sene sonuna doğru zirve yapmaya başladım. 

Uygulamaların popülerliğini yitirmesi, düşük puanlamalar kullanımın azalması en sıkıntılı konular. Hele de bazı kullanıcıların uygulamayı farklı yorumlayıp düşük puan vermesi sizi çileden çıkartabiliyor.

Bu arada bir ayı yüksek gelirle geçiriyor olmanız artık kurtardığınız anlamına gelmiyor. O ay ki reklam değerleri ve/veya sizin uygulamalarınızın popülerliği de artmış olabilir. 

İlleryollar' dan sonra yaptığım Tv Turk televizyon rehberi uygulaması ile gelirlerimi bir parça daha artırmaya başlamıştım. Uygulama popülerliği başlangıçta iyi olsa da sonradan gelen yorumlarla uygulamada geriye gidiş başlamış oldu. Tabi bu yorumların hepsi haklı değildi. Açıklamasında rehber olduğunu belirtsem de aşağıdaki yorumlardan kaçamadım.


Tabi bu yorumların fazla oluşu diğer kullanıcıları o kadar etkilemiş ki bir kullanıcıdan çok farklı bir yorum da aldım. Biraz müstehcen olduğu için karalama yapmam gerekti.



Sonuç olarak bugün uygulamalardan para kazanmaya devam ediyorum. Henüz milyoner olmuş değilim ama her geçen gün uygulama portföyümü genişletmeye çalışıyorum. Sadece reklam amaçlı içi boş uygulama da yapmak istemiyorum markette kalıcı ve belli seviyede kalmak istiyorum. Para kazanılıyor mu? Evet kazanılıyor. Çok para kazanır mısın? Ben kazanmadım ama kazanılabileceğini görüyorum. Sadece çalışmak ve biraz da şans diyelim.

Android RadioGroup, RadioButton ve ImageView (Resim)

Geçen gün bahsettiğim android uygulamalarını hayata geçirirken bazı sorunlarla karşılaştım ve bunları sizinle paylaşmak istedim. Öncelikle uygulamada çocukların öğrendiklerini test etme amaçlı bir test arayüzü (activity) yazmak istedim. Test dediğimiz zaman programcı olarak aklımıza gelmesi  gereken elemanlardan (component) ilki radiobutton ‘ dur.

RadioButton, RadioGroup ile kullanıldığında size otomatik olarak çoktan seçmeli bir arayüz oluşturacaktır. RadioGroup içerisine atayacağınız her radiobutton (seçenek) için radiogroup size sadece birisini seçmenizi sağlayacaktır. Zaten test arayüzünden bizim de istediğimiz budur, yani soruya seçenekler içerisinden verilecek tek cevap.

Basitçe kodlayacak olursak;

final RadioGroup radioGroup = new RadioGroup(this); radioGroup.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)); for (int i=0; i<4; i++) { final RadioButton radio = new RadioButton(this); radio.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); int resid = i; Drawable image=getResources().getDrawable(resid); image.setBounds(0, 0, 128, 128); radio.setCompoundDrawables(image, null, null, null); radio.setText(" "); radioGroup.addView(radio); }
             
Yazdığımız kod sonucunda yandaki gibi soru seçenekleri oluşacaktır. Yazı (text) bazlı seçenekler için gayet basit bir çözüm oluyor.

Peki ya yazı değil de seçenekleri resimden oluşturmak istersek nasıl kodlama yapmamız gerekecek?

Öncelikli olarak belirtmek isterim araştırmadan kafamdakilerle olaya başladığımdan sürekli sorun yaşadım. Toplamda 3 farklı yol izleyerek kendimi gereksiz yere yordum ve sonuncu seçenekte doğruyu buldum. Gerçi doğruyu bulduğumda da bir başka bug ile karşılaştım ama sonunda sorun çözülmüş oldu.
Konuyu fazla uzatmadan direkt olarak size çözümü belirtip arkasından diğer uygulamalardaki sıkıntıları sizinle paylaşacağım.

RadioButton üzerinde setCompoundDrawables() adlı  fonksiyonu kullanarak RadioButton üzerine yazıdan önce veya sonra resim çizebiliyoruz. Aşağıdaki kodda drawable klasöründe bulunan bir resimi kullanarak radioButton (seçenek) üzerine resim çizmiş oluyoruz.


Yazıyı boş bırakınca veya boşluk olarak kullanınca seçeneğimiz ( radiobutton) sağdaki şekilde görünecektir. Bu sayede resimli seçenek oluşturmayı basitçe halletmiş olacağız. Yalnız burada daha önceden sözü geçen bug olayından bahsetmek isterim. RadioButton özelliklerinden padding seçeneğini kullandığınızda yani kenar radiobutton için kenar boşluklarını ayarlamak istediğinizde alakasız biçimde oluşturduğunuz seçenek aşağıdaki gibi olacaktır.

Ne yaptıysam ne kadar araştırdıysam da buna bir çözüm bulamadım. En son çözüm olarak kenar boşluklarından (padding) vazgeçtim ve düzeldi.

Aslında resimli seçenek oluşturma çözümü yukarıda bahsettiğim şekilde gerçekleştirilebilir. Tabi bu yöntemi bulmadan önce iki farklı ve zahmetli çözümle yola çıktım. Kısaca yöntemlerden ve yaşadığım sorunlardan bahsedelim.

İlk olarak seçenekler için kullandığım radio button için background özelliğine bitmap resim yerleştirmek istedim. Hayvan resimlerini radiobutton için ölçeklendirip arkaplan resmi olarak kullandım.

float ratio = 0; Bitmap bitmap = BitmapFactory.decodeResource(this.getResources(), Integer.valueOf(question.OptionResources.get(i).Resource.toString())); if(bitmap.getHeight()>=bitmap.getWidth()) {
ratio = Float.valueOf(ImageSizeOption) /bitmap.getHeight(); int newwidth = (int)(bitmap.getWidth()*ratio); bitmap = Bitmap.createScaledBitmap(bitmap.copy(Bitmap.Config.ARGB_8888, true), newwidth, ImageSizeOption, false); } else { ratio = Float.valueOf(ImageSizeOption) /bitmap.getWidth(); int newheight = (int)(bitmap.getHeight()*ratio); bitmap = Bitmap.createScaledBitmap(bitmap.copy(Bitmap.Config.ARGB_8888, true), ImageSizeOption, newheight, false); } int radiowidth = Constants.pixelFromDp(this, 60); Bitmap layoutbitmap = Bitmap.createBitmap(ImageSize*2, bitmap.getHeight(), Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(layoutbitmap); canvas.drawBitmap(bitmap, radiowidth, 1, null); BitmapDrawable bit = new BitmapDrawable(layoutbitmap); radio.setBackgroundDrawable(bit); radio.setText(" "); radioGroup.addView(radio);

Görüldüğü üzere kod bir önceki koda göre oldukça büyüdü ve yapılan işlem sayısı arttı. Resmi ekran boyutuna göre ölçeklendirmek için kontroller geldi. Sonuç olarak bu işlem sayesinde resimli seçeneği oluşturmuş oldum.


Bu yöntemin dezavantajı yavaş kalması, bazı ekranlarda ölçeğin bozulması ve bazı telefonlarda arka plan resminin gözükmemesi oldu. Bu nedenle bu yöntemden vazgeçtim.


Bir de RadioGroup kullanmadan LinearLayout kullanarak RadioButton ve ImageView ikilisini yan yana getirerek seçenekleri oluşturmaya çalıştım. RadioGroup kullanmadığım zaman resimler ne kadar güzel görünse de seçeneklerin hepsi aynı anda seçilir hale geldi.

Seçeneklerin tek tek seçilebilmesi için radiogroup elemanının otomatik olarak yapacağı işi kendim kodlayarak yeni kontrol ekleyerek yapmaya çalıştım. Sonuç olarak yaptm ama kod bir hayli büyüdü. Çözüm güzel olsa da yönetilebilirlik azaldığı için bu yöntemden de vazgeçmiş oldum.

Meyveler ve Hayvanlar

Merhabalar,
Tembel developer olarak .Net platformu (C#) ve hobi olarak android platfomu üzerine kod yazmada tembellik ettiğimi söyleyebilirim. Son olarak android uygulamalarıma iki yeni uygulamayı daha eklemiş bulunmaktayım. Meyveler ve Hayvanlar uygulamaları özellikle okul öncesi çocuklar için hazırlanmış eğitici uygulamalardır.

Meyveler uygulaması ile çocuklar 20 adet meyvenin resmini ve ismini öğrenebilir. Sonra da test arayüzünü kullanarak kendisini test edebilir. Aslında test arayüzünde soruların yazılı olması sorun gibi görünse de çocuklar sorunun şeklinden nasıl cevap vereceğini hemen anlayabilmektedir.

Aynı şekilde Hayvanlar uygulaması ile çocuklar 25 hayvanın farklı resimlerini, isimlerini ve ek olarak çıkardıkları sesleri öğrenebilirler. Meyveler uygulamasından farklı olarak her hayvana ait ses test kısmına da eklenmiştir.


Tembellik etmeyip aynı tarzda bir uygulama daha çıkarmayı düşünüyorum. Artık onu da çıkardığım zaman sizinle paylaşırım. Şimdilik bu kadar görüşmek dileğiyle...

Windows Hosting Plesk 301 redirect ve .htaccess


Projelerimi yayınlamak için birçok insan gibi hosting hizmeti alıyorum. Bu hizmeti aldığım için çoğu zaman Plesk paneli ile haşır neşir oluyorum. MVC kullanarak yeni yaptığım bir site için yine hosting hizmetinden faydalandım. Sonrasında seo analizi eden sitelerden kontroller yaptım.

Kontrol sonucunda bir madde ilgimi çekti. Arama motorlarına göre bir siteye farklı url’lerden gidiş o sitenin pagerank’ını düşürüyormuş. Yani http://illeryollar.com ile http://www.illeryollar.com aynı site de olsa iki farklı bağlantı üzerinden gidildiği için puanı ikiye bölünüyormuş. Bu tavsiye edilmeyen (www , non-www problem) durum için sitenin bağlantısı bir tane olmalıymış.

Bunun üzerine yaptığım araştırmalarda 301 redirect (ana yönlendirme) işlemi karşıma çıktı. Paylaşımlı olmayan sadece size ait sunucularda Windows için IIS ayarlarına direkt olarak girip değişikliği yapabilirsiniz. Ama bir de işin paylaşımlı sunucuları yani hosting firmalarından aldığınız hizmetler kısmı var.

Plesk .htaccess file
Paylaşımlı Windows (IIS) sunucuları için kullandığınız dosya sisteminde plesk panel aracılığıyla veya kendi bilgisayarınızda “.htaccess” isimli bir dosya yaratıp içeriğini belirleyeceğiniz şartlara göre aşağıdaki şekilde değiştirmeniz yeterli olacaktır. Tabi lokalde oluşturduğunuz dosyayı ftp aracılığıyla httpdocs klasörü altına koymanız gerekecektir.
  • www ‘den non-www’ ye geçiş

    RewriteCond %{HTTP_HOST} ^www\.(.*)$ [NC]
    RewriteRule ^(.*)$ http://%1/$1 [R=301,L]
  • non-www ‘den www’ ye geçiş 
    RewriteEngine On
    RewriteCond %{HTTP_HOST} ^alanadi.com
    RewriteRule (.*) http://www.alanadi.com/$1 [R=301,L]
Bir problem de siteniz .NET4.0 ve MVC kullandığınızda ortaya çıkacaktır. Yukarıdaki tanımlamaları yaptıktan sonra non-www yani;
http://illeryollar.com adresini girdiğinizde  http://www.illeryollar.com/eurl.axd/8121c3c142fb74458da916ba07caaf17/

şeklinde saçma sapan uzantısı olan bir bağlantı ile siteniz sorunsuz şekilde gelecektir. Bu hatayı da bertaraf etmek için aşağıdaki .htaccess dosyasına yukarıdaki seçenekler yerine aşağıdakileri yazarak kaydediyoruz.
  • eurl.axd/ hatası için www ‘den non-www’ ye geçiş

    RewriteCond %{HTTPS} (on)? 
    RewriteCond %{HTTP:Host} ^www\.(.+)$ [NC] 
    RewriteCond %{REQUEST_URI} (.+)? 
    RewriteRule ^(.*)(eurl.axd/.*)$ http(?%1s)://%2/$1 [R=301,L]
  • eurl.axd/ hatası için non-www ‘den www’ ye geçiş

    RewriteCond %{HTTPS} (on)? 
    RewriteCond %{HTTP:Host} ^(?!www\.)(.+)$ [NC] 
    RewriteCond %{REQUEST_URI} (.+)? 
    RewriteRule ^(.*)(eurl.axd/.*)$ http(?%1s)://www\.%2/$1 [R=301,L]

Dilerseniz tüm değişimler http://www.htaccessredirect.net/ adresinden dosya içeriğini oluşturarak da yapabilirsiniz.


Türkiye'nin bölgeleri, illeri ve iller arası mesafeleri...

Uzun zamandır kafamı kurcalayan konulardan birisiydi MVC. Çalıştığım uygulamalarda hiç MVC ile uğraşmamıştım ve görünen o ki (elimde işin eski oluşu nedeniyle) uzun bir süre daha MVC konusuna iş yerinde giremeyecektim.

Bir de aklımda android uygulaması olarak hazırladığım iller yollar projesinden kalma bunu nasıl web ortamına taşırım işi vardı. Doğal olarak tembel bir developer'ın aklında bir çok plan proje vardır. Eskiden büyük düşünceler olsa hayata geçmedikçe projeler küçüldü. Bence iyi oldu aslında. Neyse bunu başka bir başlık altında konuşuruz.

Bu iki düşünce bir araya gelince MVC kullanarak illeryollar için bir web sitesi hazırlamak için kolları sıvadım. Şimdilerde yayına giren sitede aşağıda ismi geçen teknolojileri kullanmaya çalıştım.

  • Asp.NET MVC3 Razor syntax
  • Nhibernate 3.3
  • SQLite veritabanı
Öncelikle şunu söylemeliyim ki MVC gayet anlaşılır ve kolay uygulanabilen bir yapı olmuş. Razor sentaksına ise hemen alışabiliyorsunuz. Gözünüz korkmasın ve kesinlikle bu işlere bir yerden girin. Şu anda iş ilanlarına bakarsanız MVC uygulaması yazma şartı aranır oldu.

"MVC bana ne kattı?" veya "MVC nin bana getirisi ne?" diye soracak olursak öncelikle geliştirme zamanını kısalttı ve kodun anlaşılabilirliğini artırdı. Her zaman bahsedilen katmanlı yapı konsepti kendiliğinden hazır olarak geldiği için hemen adapte olabiliyorsunuz. İkinci olarak artık seo için olmazsa olmaz url rewrite özelliğini framework katmanında atlayıp zıplamadan elde etmiş bulunuyorsunuz. Örnek vermek gerekirse

/iller.aspx?id=61&name=trabzon şeklinde parametrik ifade yerine /iller/detay/trabzon ifadesi hemen gören göz için hem de arama motorları için daha çekici oluyor. Günümüz seo tekniklerinde de bu şekilde kullanılması tavsiye ediliyor. Ha diğer şekilde arama motorları indekslemiyor, tanımıyor mu? Elbetteki tanıyıp indeksliyor ama güncel gelişmeleri de takip etmek gerekir.

illeryollar.com ana sayfa

Velhasıl bu teknolojileri kullanarak illeryollar.com 'u hayata geçirdim. Bundan sonrası ekstra geliştirmeleri nasıl yaparım, için içindeki verileri nasıl zenginleştiririm onu düşünürüm artık.

Bu arada veriler derken veri saklama sqlite veritabanını kullandım. Dosya tabanlı küçücük bir veritabanı da olsa özellikle mobil cihazlarla birlikte popülerliği artmıştır. Veri yoğunluğunun aşırı olmadığı çok fazla bağlantı açılmayacak uygulamalar için özellikle de nhibernate ile etkileişimi kolaylıkla yapılabildiğinden tercih edebilirsiniz.

Blog işine başlıyoruz

Bugün pek işim yoktu. Son zamanda olduğu gibi geç kalmışlığın verdiği hevesle bir de blog işine gireyim dedim ve ufak bir araştırmadan sonra blogger ile blog hesabımı oluşturmuş oldum.