Android NDK ile uğraşırken dikkat edilecekler :)

Evet arkadaşlar C++, GitHub derken nereden çıktı bu NDK diyebilirsiniz ama eğer elinizde hazır C++ kütüphaneleriniz var ve bunu hızlı ve performanslı bir şekilde Android platformunda kullanmak istiyorsanız en iyi yöntem NDK (Native Development Kit).  NDK her ne kadar google tarafından resmi olarak önerilmese de, yüksek performans ve çoklu platform desteği için olmazsa olmaz. Ben de bir süredir geliştirmekte olduğum 2B uygulama alt yapımı android üzerinde de kullanmak istiyordum ve tekrardan bu mecraya bir dönüş yapmış oldum.

Bundan yaklaşık iki üç sene öncesinde tez ve benzeri çalışmalar için bir çok üçüncü parti kütüphaneyi ve kendi yazılım alt yapımı androide taşımak için uğraşmıştım ve hakikaten ömrümden ömür gittiydi. O sıralar CygWin veya eclipse üzeirnde ilk etapta başlamış daha sonraları ise internet üzerinden bulduğum MSBuild scriptleri ile visual studio üzerinden bu işi halletmeye çalıştıydım (veya kullanmaya çalışıyordum 🙂

Neyseki visual studio 2015 ile birlikte microsot artık Android desteğini resmi olarak Visual Studio’ya getirdi. Tabi buradan gözleriniz çok ta parlamasın 🙂 halen çoğu şey çok açık değil ve saç baş yolduracak bir çok durum olabiliyor. İşte bu ilk yazımı da buna ayırayım dedim 🙂

Yani MS ortamında Visual Studio kullanarak NDK kullanımında dikkat etmeniz gerekenler.

Öncelikle eğer salt hedef platform android ise şunu belirtmekte fayda var, bence VS yanında muhakkak android studio gibi bir araç öğrenmeniz ve kotline de girmeniz faydalı olacaktır. Ama amacınız benim gibi bir şekilde android platformunda uygulamanızı çalıştırmak ise VS işiniz görecektir. Elbette android ve NDK alt yapısı ile ilgili bilmeniz gerekenler var (bunları kısaca bir sonraki yazımda anlatmayı planlıyorum) fakat beklentilerinizi VS açısından çokta yüksek tutmayın. Çünkü VS biraz NDK ve ilgili teknolojileri geriden takip ediyor. En son VS 2017.15.5.2 güncellemesi halen Ndk13b yi destekliyor (ha burada el ile en son NDK yi burada kullanmaya çalışabilirsiniz ama açıkçası benim en son Ndk14 ile yaşadığım deneyim hiç iyi değildi :). Bu arada yeni 2017.15.6 güncellemesi ile Ndk15c desteklenecekmiş. Her neyse konumuzdan fazla sapmadan VS NDK kullanımına geri dönelim. Burada VS ile derlemeyi planladığım kütüphane SDL 2.0.7.

SDL yaygın olarak bir çok geliştirici tarafından kullanılan ve platform bağımsız yazılım ve oyun geliştirmenize yardımcı olan bir kütüphane.  Benzeri GLFW, GLUT, GLU ve SFML ‘den ziyade SDL i kullanmamın temel bir kaç sebebi var (bu arada diğer kütüphanelerin hemen hemen tümü ile geliştirme yaptım özellikle GLFW ve GLUT ile fakat kendi kütüphanem için SDL de karar kıldım):

  • Öncelikle OpenGL 3/4+ desteği (ör. SFML 3+ desteklemiyor),
  • Android desteği (GLFW bu desteği sunmuyor ama açıkçası diğerlerine göre çok daha temiz ve kullanışlı),
  • Oldukça kapsamlı sistem ve ek kabiliyetler sunuyor (Opengl yanında kendi çizim API’leri de mevcut, SFML de benzeri yelpazeyi sunuyor bu arada),
  • Yancı bir çok kütüphanesi var (SDL_Mixer, SDL_Image, SDL_NET, etc. Bu konuda en geride kalan GLFW, GLU ve GLUT),
  • Oldukça olgun ve geniş bir kullanıcı kitlesi var.

Bu arada bu yazımda faydalandığım sayfalardan biri de (http://trederia.blogspot.com.tr/2017/03/building-sdl2-for-android-with-visual.html) olmuştur kendisi çok güzel bir şekilde SDL’i VS ile nasıl derleyebileceğimizi için ingilizce olarak anlatmaktadır. SDL benzeri kütüphaneleri VS ve NDK ile nasıl derleyebileceğimiz ile ilgili ben de ayrı bir yazı yazacağım onun için burada o konuya girmiyorum.

Evet şimdi kısa kısa NDK ile geliştirme yaparken hayati olan ve size faydalı olacak bilgilere gelelim:

NDK hakkında genel bilgiler:

Öncelikle NDK nedir ile başlayalım:

  • NDK, Android için C/C++ kullanarak native kod geliştirmenize olanak sağlayan bir API’dir.
  • NDK ile yazılım geliştirmeye başlamadan önce Android platformu ile ilgili genel bilgileri edinmeniz faydalı olacaktır. Bu noktada özellikle http://www.vogella.com/tutorials/android.html sayfasını sizlere öğreneceğim. Buradan;
    • Android işletim sistemi mimarisi, genel yapı taşları, Dalvik VM
    • Android software layers
    • Application, activity, service, broadcast receiver ve content provided kavramları (özellikle activity).
    • Android (ve dahi NDK) uygulamalarına ilişkin genel ayarlama ve konfigürasyonların yapıldığı AndroidManifext.xml dosyalarına aşina olmalısınız.
    • Android.mk (kısaca android NDK uygulamaları için makefile), bu dosya içerisinde kullanılan derleme, bağlama (link) ve diğer kullanılabilecek parametreler (aşağıda kısa bir kaç örnek vereceğim),
    • NDK uygulamasının derlenmesinde uygulama seviyesinde yapılan bazı ayarlar için Application.mk ya aşina olmalısınız (aşağıda kısa bir kaç örnek vereceğim),
    • Android sürümleri ve hedef platformları, AVD (Android Virtual Device), kısaca Android Debug Bridge (ADB) kavram ve araçları.
    • NDK uygulamaları (native activities) iki şekilde kullanılabilirler direk native activiteler başlatılarak (NDK üzerinden ve hiç java kodu yazmadan) ya da Java ile yazılacak olan bir wrapper activity aracılığı ile gerçekleştirilebilir. Bu seçim AndroidManifest içerisinden hasCode parametresi ile gerçekleştiriliyor.
    • Eğer arayüz uygulamalarını Java kullanarak geliştirecek iseniz veya Java kısımları da olacak ise JNI ve Java / Native kod haberleştirme kısımlarına da bir bakmanız faydalı olacaktır. Bu arada küçük bir not. Çalışma esnasında Java ile native kısımlar arasındaki etkileşimleri ne kadar az tutarsanız o performans açısında iyi olur.
  • NDK, SDK manager aracılığı ile kurulabilir (https://developer.android.com/ndk/guides/index.html adresinden daha detaylı bilgilere ulaşabilirsiniz).
  • Android studio, komut satırı ve Visual Studio kullanarak NDK uygulamaları geliştirebilirsiniz. Eğer ilgili kütüphaneye ilişkin elinize Android.mk dosyası var ise veya taşıyacağınız kod veya kütüphaneler çok büyük ve karmaşık değil ise komut satırını tercih edebilirsiniz.
  • Yukarıdaki sayfa yanında http://www.indigoo.com/dox/mobdev/01_Android/Android-NDK.pdf sitesinden de NDK ile ilgili bilgiler edinebilirsiniz.

Neden NDK:

Bunlarından yanında NDK ile uygulama geliştirmeden önce aşağıdakilerden en azından biri sizin amaçlarınız arasında değil ise tekrar düşünmenizde fayda var.

  • Üst seviye performans temini: Android uygulamalarından hele ki CPU ağrılıklı iş yapıyorsanız ya da CPU bağımlı kısımlarınız var ise bunları C++ ile geliştirmek size performans kazanımı sağlayacaktır.
  • Yüksek performans API’lerini kullanma: Özellikle OpenGL ES ve Vulkan alt yapısına ilişkin detaylı API’ler NDK ile sunulmakta. Bu sebeple çoğu çoklu platform oyun geliştiricileri NDK’yi kullanmaktadırlar.
  • Popüler veya mevcut C/C++ kütüphanelerini kullanmak: C/C++ için uygulama geliştiriyor iseniz internet üzerinde birçok hazır kütüphane de kullanıyorsunuzdur (boost, SDL, GDAL, OpenGL, vb) ve bunların büyük bir kısmının Java portları da bulunmayabilir. Eğer bunları uygulamanızda kullanmak istiyorsanız da NDK takip etmeniz gereken yol.
  • Var olan kodu kullanmak: Yazımın başında da bahsettiğim gibi bence NDK kullanımının en önemli sebeplerinden biriside mevcut kodları hızlı bir şekilde kullanılabilmesine olanak sağlaması. Tabi burada kodunuzun çok fazla platform bağımlı olmaması gerekiyor.

Dikkat Edilmesi Gereken Diğer Hususlar:

Şimdi gelelim diğer dikkat edilmesi gereken hususlara:

  • Visual Studio kurulumu yaparken “C++ ile masaüstü uygulama geliştirme”, “C++ ile mobil uygulama geliştirme” şeçeneklerini seçtiğinizden emin olun.
  • Hedeflediğiniz android platformu için gerekli SDK’ları (API düzeyi diye VS kurulumunda ifade ediliyor) ve sanal emülatörleri kurun (Intel hızlandırılmış yürütme yöneticisi de dahil).
  • Hangi VS, hangi NDK sürümü ile hangi Android platformlarını kullanacaksınız? Bunları belirleyin ve olabildiğinde değiştirmeyin. Özellikle Visual Studio güncellemelerini yapmadan önce gelen değişikliklere bakın. Mevcut VS ile Android NDK R13b destekleniyor ve şu ana kadar bunun ile ilgili bir sıkıntı yaşamadım.
  • Eğer intel tabanlı bir işlemciye sahip makine kullanıyor iseniz. X86 tabanlı ve HAXM (Hardware Accelerated Execution Manager) kullanan bir sanal cihaz (emülatör) oluşturun. Bunlar ARM tabanlı olanlara göre çok daha hızlı çalışmakta ve OpenGL ES 2.0 desteği de sunmaktalar. Kurulumu yukarıdaki seçenek ile yada https://software.intel.com/en-us/blogs/2014/10/20/how-to-ensure-you-are-using-intel-haxm-for-android-emulator. de bahsedilen adımlar ile gerçekleştirebilirsiniz.
  • Her zaman basit ama çalışan bir örnek elinizin kenarında bulunsun.
  • Visual Studio kullanarak çalışırken yapacağınız uygulama ayarlarını hangi platform (X86, ARM, X64) ve konfigürasyon (Debug, Release) için yaptığınıza dikkat edin. Mümkünse her platform ve konfigürasyon için ayarları gerçekleştirin ve çalışır halde tutun.
    • Platform/ABI: Bir önceki başlıkta anlattığım hususlara baktı iseniz ABI’larin ne olduğunu hemen hatırlayacaksınız. Mobil cihazların çoğu farklı işlemci ve komut setleri kullanmakta. İşte bu ikiliye android dünyasında ABI (Application Binary Interface) denilmekte. Bu ABI’lar uygulamanın çalışma zamanında alt yatan alt yapı ile nasıl haberleşeceğini tanımlamakta ve gerçekleştirmektedir. Bu konu ile ilgili daha detaylı bilgi için https://developer.android.com/ndk/guides/abis.html‘e başvurabilirsiniz. Şu an desteklenen ABI’lar ve ilgili komut setleri şu şekilde:
      • armeabi (ARMV5TE and later, Thumb-1)
        • NDK r17 ile kaldırılacak.
        • Visual Studio içerisinde platform olarak yok
      • armeabi-v7a (armeabi, Thumb-2, VFPv3-D16 Other, optional)
        • ARMv5, v6 cihazları ile uyumlu değil.
        • Visual Studio altında ARM olarak seçilebilir
      • arm64-v8a (AArch-64)x86 (IA-32, MMX, SSE/2/3, SSSE3)
        • Visual Studio altında ARM64 olarak seçilebilir
      • x86 (IA-32, MMX, SSE/2/3, SSSE3)
        • Visual Studio altında x86 olarak seçilebilir
      • x86_64 (x86-64, MMX, SSE/2/3, SSSE3, SSE4.1, 4.2, POPCNT)
        • Visual Studio altında x64 olarak seçilebilir
      • mips (MIPS32r1 and later)
        • NDK r17 ile kaldırılacak
      • mips64 (MIPS64r6)
        • NDK r17 ile kaldırılacak
  • Ne tip bir proje oluşturacağınız dikkat edin. VS üzerinden temel olarak üç proje geliştiriyor olacaksınız. Seçtiğiniz bu proje tipi ışığında aşağıda gösterilen ayarlar ekran görüntüsündeki “Configuration Type” değişecek.

    Visual Studio Android Proje Şablonları

    • Basic Application
      • Yüklenebilir Java + Native kod içeren bir android uygulaması oluşturmanız için gereken proje tipidir.
      • Bu projenin çıktısı android yüklenebilir paketidir.
      • VS ile bu paketi VS içerisinden bağlı olan bir donanıma veya emülatöre yükleyebilir, debug edebilirsiniz.
      • Java android activity sınıfı da oluşturulur.
      • Proje dizin yapısı ve temel sınıflar otomatik olarak oluşturulur (androidmanifest.xml, build.xml, Android1.java), etc.
    • Native-Activity Application
      • Herhangi bir Java kodu yazmadan yüklenebilir sadece Native temelli bir android uygulaması oluşturmanız için gereken proje tipidir.
      • Bu projenin çıktısı android yüklenebilir paketidir.
      • VS ile bu paketi VS içerisinden bağlı olan bir donanıma veya emülatöre yükleyebilir, debug edebilirsiniz.
      • ANativeActivity kullanabilmeniz için gerekli olan hazır c dosyaları oluşturulur.
      • Proje dizin yapısı ve temel sınıflar otomatik olarak oluşturulur (androidmanifest.xml, build.xml, android_native_app_glue.c/h, main.cpp), etc.
    • Android Static Library
      • .a uzantılı (windows platformunda .lib uzantılı olan) statik kütüphaneler oluşturmanıza yardımcı olur.
      • Bu kütüphaneleri daha sonra .so dinamik kütüphaneler veya android uygulamalarınızda kullanabilirsiniz.
      • .so dinamik kütüphanelerinden farklı olarak uygulamayı oluştururken proje ayarlarında belirtmeniz gerekiyor.
    • Dynamic Shared Library
      • Native c++ dinamik kütüphanesi oluşturmanızı sağlar.
      • Çıktının uzantısı .so olur.
      • Uygulama içerisinden ilgili API’leri kullanarak uygulama içerisinden istediğiniz zaman yükleyebilirsiniz.
  • Visual Studio da aşağıdaki ayarlara dikkat edin.
    • Compiler
      • Android NDK r11 ile birlikte gcc çıkarılacak şekilde işaretlenmiş (ileriki sürümlerde çıkarılacak) ve en son gcc 4.9 desteklenmekte. Gcc yerine şu anda clang/llvm desteklenmekte. Bu sebeple Clang kullanmakta fayda var.
    • STL
      • Android NDK tarafından mevcut sürümde libc++gnustl, ve stlport desteklenmektedir. Bunlardan en günceli libc++ yani (LLVM’s C++ standart kütüphanesidir), bu kütüphane ileride NDK ile kullanılabilecek tek kütüphane olacağından bunu kullanmanızı tavsiye edeceğim. VS ile de bir sıkıntı çıkarmamakta, hatta en güncel C++ standartlarını desteklemekte. gnustl ise GCC’ye oldukça bağımlı ve bu sebeple tercih edilmiyor. Bu üçü arasında en eski kalanı ise stlport. stl port geliştirme faaliyetleri artık olmadığından ve yeni C++ standartlarını da desteklemediğinden sonraki NDK sürümlerinde çıkarılacak.
      • C++ uygulamaları içerisinde tek bir tip STL kütüphanesi kullanmalısınız. C++ uygulamaları içerisinde aynı fonksiyon veya nesnenin birden fazla kopyasının bulunması güvenli değildir. Buna One Definition Rule‘da deniliyor.
    • Target API Level
      • Burada hedeflediğiniz
  • Diğer ayarlar
    • Exception desteği,
      • C/C++ -> Code Generation altında
    • C++ 0x ve 0y destekleri
      • C/C++ -> Language altında
    • Enable Run-Time Type Information
      • C/C++ -> Language altında
    • Statik kütüphane eklenme sırası (evet bu da önemli)
      • Linker -> Input altında
      • Uygulamayı oluşturma sırasında link hataları alıyor iseniz ilk bakmanız gereken yer burası
  • .so uzantılı dinamik kütüphanelerin ve assetlerin APK içerisine dahil olduğundan emin olun
    • .so uzantılı dinamik kütüphaneleri VS projeleri altından References alanına ekleyerek pakete dahil edebilirsiniz. Bu şekilde VS içerisinde bulunan projeleri ekleyebilirsiniz.
    • Bir diğer yöntem ise el ile eklemek
      • Bir önceki maddede anlatılan yöntem haricinde VS de bulunmayan veya el ile eklemek istediğiniz dinamik kütüphaneleri eklemek için izleyebileceğiniz bir diğer yöntem ise uygulama projesi altında libs dizini oluşturmak.
      • Burada libs dizini içerisine uygulamanızı çalıştırmayı planladığını her bir platform için (x86_64, x86, armeabi-v7a , armeabi gibi) ilgili dizinleri  oluşturup, bu dizinler içerisinde dinamik kütüphaneleri eklemeniz gerekmekte (her bir platform için dinamik kütüphaneleri oluşturmalısınız, aksi takdirde uygulamanız çalışmaz ya da exception yiyebilirsiniz). Örneğin x86 mobil cihazlar için SDL.so’yu “proje dizini/libs/x86/SDL.so” şeklinde yerleştirmelisiniz.
      • Daha sonra bu dosyaları VS projesi içerisine de eklemelisiniz, aksi takdirde paket içerisine eklenmezler.
    • Android NDK uygulamaları varsayılan olarak uygulamada kullanacağınız dosyalar için assets dizini içerisine bakar. Bu dizine eklenen verileri pakete dahil etmek için bir .so dosyaları gibi bunların da VS e eklenmesi gerekmekte.
  • AndroidManifest.xml ayarları:
    • Aktivite ismini doğru girdiğinizden emin olun (örneğin ” <activity android:name=”.SDL2_Application” … “)
    • Gerekli hakları tanımlayın
    • En az ve en fazla desteklenen hedef android platformlarını girin ve bunların VS Target API level ile uyumlu olduğundan emin olun.
  • Ve son olarak sabırlı olun. Eğer normalde çalışan veya çalışması gerektiğini düşündüğünüz bir durum var ise biraz ara verin ya da temiz bir kurulum ile tekrar deneyin. Sabırlı olun (tekrar 🙂

Güncelleme (01/07/2018):

Evet arkadaşlar uygulamalarınız geliştirdikten sonra ihtiyaç duyacağınız hususlardan birisi de dinamik kütüphanelerin kod içerisinde yüklenmesi buraya kadar her şey açık. Gel görki dlopen API’si ile libs dizinine eklediğiniz .so kütüphanelerinizi yüklemeniz için kullanacağınız adres ile ilgili ufak bir ayrıntı var. O da bu kütüphanelerin android işletim sistem içerisinde “/data/data/PackageName/lib/” dizini altına yerleştirildiği 🙂 Burada PackageName sizin uygulamanız ismi (ör. com.SDL_Application bunun için github’a koyduğum SDL kodu içerisine bir API ekledim, oradan dinamik olarak uygulamanızın paket ismini öğrenebilirsiniz. Evet biraz bulması zor oldu keza kendisi bir implementasyon detayı imiş 🙂

7 Comments Android NDK ile uğraşırken dikkat edilecekler :)

  1. AvatarOnur Acar

    Elinize sağlık, faydalı bir yazı olmuş. Size mail yoluyla ulaşmam mumkun mudur acaba, konu ile ilgili bir kaç sorum olacakti. Internette yaptıgım araştırmalarda istediğim sonuclara ulaşamadım, yardimci olursanız çok memnun olurum. Teşekkür ediyorum.

    Reply

Bir cevap yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

This site uses Akismet to reduce spam. Learn how your comment data is processed.