Android

Windows'da Android NDK Kullanımı

NDK (Native Development Kit); Android uygulamalarımızda C veya C++ dillerinde yazılmış olan kodlarımızı kullanabilmemize olanak sağlayan bir araç setidir. Android 201 eğitimi içinde bu konudan kısaca bahsetmiştik. NDK kullanımındaki ana amaç, uygulama katmanında performans artışı ...

Yasin Kafadar |

06.12.2013

NDK (Native Development Kit); Android uygulamalarımızda C veya C++ dillerinde yazılmış olan kodlarımızı kullanabilmemize olanak sağlayan bir araç setidir. Android 201 eğitimi içinde bu konudan kısaca bahsetmiştik.

NDK kullanımındaki ana amaç, uygulama katmanında performans artışı sağlamaktır. Öte yandan native kodları (C veya C++ dilinde yazılmış kodlar) kullanmak, çoğu uygulama için performans artışı sağlamaz. Bu yüzden de kullanmadan önce yaptığımız işlemin gerçekten CPU'yu yoran bir işlem olup olmadığına karar vermemiz gerekir. Bu konuda daha fazla bilgi için bu bağlantıdaki giriş kısmını okumanızı tavsiye ederim.

Kısa bir girişten sonra, NDK'yi Windows üzerinde ek başka bir araca gerek duymadan nasıl kullanacağımızı anlatmaya başlamak istiyorum. Öncelikle buradan Windows platformunuzun tipine göre gerekli zip dosyasını indirip bilgisayarınız üzerinde herhangi bir dizine açmanız gerekiyor. Ben "android-ndk-r9b-windows-x86_64.zip" paketini indirip bu dizine açtım "D:\dev\Android\android-ndk-r9b". İndirilen zip dosyasının boyutu 450 MB’dan biraz fazla, o yüzden indirme işlemi zaman alabilir.

İndirme işlemi devam ederken Eclipse’i açıp yeni bir proje yaratabiliriz. Ben “AndroidNDKDemo” adında bir proje yarattım. Bütün kodlara bu adresten ulaşabilirsiniz. Projeyi yarattıktan sonra projenin ana dizini altına “jni” isimli bir klasör yaratıyoruz. “jni” klasörünün içine “Android.mk” isimli boş bir dosya yaratıyoruz. Şimdilik böyle bırakıyoruz, ileride içini dolduracağız. Son durumda projemizin görünümü aşağıdaki gibi oldu:

Örnek olması açısından üslü sayıları gerçekleyen bir C programı yazacağım. Kısaca programın yapacağı sayıyı ve üssünü gönderip sonucu bize dönecek (Ör: 35 -> 243).

Yavaş yavaş kod yazmaya başlıyoruz. Öncelikle bir tane wrapper java sınıfı yaratıyoruz. Bu sınıfın içinde birazdan yazacağımız C kodlarını içeren "exponential" kütüphanesini yüklüyoruz. Ayrıca native olarak belirttiğimiz method ile de C kodundan direk çağıracağımız fonksiyonumuzu belirtiyoruz. Sonuç olarak aşağıdaki gibi bir java sınıfı yazmış oluyoruz.

[code]package tr.com.turkcellteknoloji.demo.ndk;
public class ExponentialWrapper {
    // Load library
    static {
        System.loadLibrary("exponential");
    }
    public static native int exponential(int number, int power);    
}[/code]

Native metodu belirledikten sonra bu java sınıfını derleyerek C kodumuz için header dosyasını oluşturuyoruz. Oluşturulan bu header dosyasının içinde "exponential" metodumuzun bir prototipi bulunmaktadır. Java sınıflarının nasıl derleneceği konusu Android 101'in şu dersinde anlatılmıştı. Komut satırından "ExponentialWrapper" sınıfımızın olduğu dizine gidip "javac" komutunu çalıştırıyoruz. Derlenmiş dosyaları ben direk D'nin altına atacak şekilde yazdım komutu.

Kodu derledikten sonra class dosyasından C header’ını oluşturabiliriz. Burada tam paket adını yazdığımızdan emin olalım.

Header dosyasını oluşturduktan sonra istediğimiz ismi verebiliriz. Ben bu örnekte "exponential.h" olarak değiştirdim ve dosyayı jni klasörünün içine attım. "exponential.h" dosyası aşağıdaki gibi oldu.

[code]

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class tr_com_turkcellteknoloji_demo_ndk_ExponentialWrapper */

#ifndef _Included_tr_com_turkcellteknoloji_demo_ndk_ExponentialWrapper
#define _Included_tr_com_turkcellteknoloji_demo_ndk_ExponentialWrapper
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     tr_com_turkcellteknoloji_demo_ndk_ExponentialWrapper
 * Method:    exponential
 * Signature: (II)I
 */
JNIEXPORT jint JNICALL Java_tr_com_turkcellteknoloji_demo_ndk_ExponentialWrapper_exponential
  (JNIEnv *, jclass, jint, jint);

#ifdef __cplusplus
}
#endif
#endif[/code]

“jni” klasörünün altına “exponential.c” adında bir dosya açıyoruz ve header dosyasından exponential metodunun imzasını bu C dosyasının içine kopyalayıp yapıştırıyoruz. Daha sonra bu metodun içini dolduruyoruz. Son olarak exponential.c’nin içi aşağıdaki gibi oluyor:

[cpp]#include "exponential.h";

JNIEXPORT jint JNICALL Java_tr_com_turkcellteknoloji_demo_ndk_ExponentialWrapper_exponential
  (JNIEnv *je, jclass jc, jint number, jint power){
    jint i=0;
    jint result = 1;
    for(i = 0; i<power; i++){
        result *= number;
    }

    return result;
}[/cpp]

Son olarak daha önce oluşturduğum Android.mk dosyasının içini dolduracağız. Bu dosya C dosyalarının nasıl derleneceğini bildiren bir makefile’dır. İçi aşağıdaki gibi olacak:

[cpp]LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE := exponential

LOCAL_SRC_FILES := exponential.c

include $(BUILD_SHARED_LIBRARY)[/cpp]

Gerekli kodları yazdıktan sonra şimdi derleme aşamasına geldik. Normalde JNI'da C dosyalarını derleyip shared library oluşturmak için gcc –shared parametresi ile derlemek gerekirdi fakat biz Android cihazlar için ndk-build betiğini kullanacağız.

Derlemek için ndk-build'in tam dosya yolunu kullanmak gerekiyor. Benim bilgisayarımdaki yeri "D:\dev\Android\android-ndk-r9b\ndk-build". Derlemek için komut satırında projenin bulunduğu dizine gidiyoruz ve ndk-build çağırıyoruz.

Projemiz başarılı bir şekilde derlendikten sonra bir kere projemizin üzerine gelip yeniliyoruz. Libs klasörünün altına armeabi klasörünün oluştuğunu ve onun içinde derlenmiş C dosyasını, .so uzantısı ile göreceksiniz.

Şimdi sıra C dili ile yazdığımız metodu activity içinden çağırma kısmına geldi.

Örnek activity_layout kodları:

[cpp]

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_margin="20dp"
    android:orientation="vertical"
    tools:context=".MainActivity" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Sayı:" />

    <EditText
        android:id="@+id/number"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:text="Üs" />

    <EditText
        android:id="@+id/power"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <Button
        android:id="@+id/calculate"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Hesapla" />
    
    <TextView
        android:id="@+id/result"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:textSize="20sp" />

</LinearLayout>
Örnek MainActivity sınıfının kodları:
public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        final EditText edtNumber = (EditText) findViewById(R.id.number);
        final EditText edtPower = (EditText) findViewById(R.id.power);
        final TextView txtResult = (TextView) findViewById(R.id.result);
        Button btnCalculate = (Button) findViewById(R.id.calculate);
        btnCalculate.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                int number = Integer.valueOf(edtNumber.getText().toString());
                int power = Integer.valueOf(edtPower.getText().toString());
                int result = ExponentialWrapper.exponential(number, power);
                txtResult.setText("Sonuç:" + result);
            }
        });
    }

}[/cpp]

Örnek olarak 3 ve 5 sayılarını giriyoruz.

Sorularınızı bekliyorum. :)

Yasin Kafadar |

06.12.2013

Yorumlar

Emre AYDIN
10.07.2014 - 05:42

yeniden isimlendirmeniz lazım. benim kullandığım örn: "com.ea" bunu nasıl yapıcam derseniz src klasörü altındaki com.example.ornek buraya sağ tıklayıp recaftor -> rename yaparak burdan yeniden adlandırabilirsiniz.

nevzat
16.07.2014 - 04:51
başlangıçta yeni proje oluştururken example yazan yeri değiştirmemiz yeterli
nevzat
16.07.2014 - 05:03

başlangıçta yeni proje oluştururken example yazan yeri değiştirmemiz yeterli

Ekrem
18.07.2014 - 10:28

[code]Javah -jni   aaa.ndk.nativedevelopment.ExponentialWrapper[/code].

Bunda class not found hatası alıyorum. Eclipse tool ile header dosyası oluşturmayı denedim yine aynı hatayı aldım. 

Bu hatayı nasıl çözebilrim, denemediğim yöntem kalmadı nerdeyse.

sercan kaya
11.03.2014 - 11:21

uygulamamı play store da yayınlayabilmek için lisans almaya çalışıyorum "com.example" kısıtlanmış olduğundan farklı bir paket adı kullanmanız gerekiyor. hatası veriyor nasıl çözebilirim yardımlarınızı bekliyorum

Ebubekir
18.01.2014 - 01:34

javah -jni com.example.androidndkdemo.ExponentialWrapper 

kodunu çalıştıramıyorum yardımcı olabilir misiniz