11 Haziran 2016 Cumartesi

Açık kaynak olan inanılmaz servislerden Wikidata API

Wikipedia çok yaygın olarak kullanılan bir online ansiklopedi haline geldi. Bunda içerisindeki uçsuz bucaksız sayıda başlığa sahip olmasının yeri büyük. Bu platformun önemi kavranmış olmalı ki Wikidata ismiyle tüm wiki sitelerinin verilerini (wikipedia, wikinews ..) yapılandırılmış olarak depolayan ve bizlere sunan bir proje geliştirilmiş.

Wikidata API wikipedia'da bulunan herşeyi sınıflandırılmış olarak sunan istemeyeceğimiz kadar anlamlı veri elde edebileceğimiz inanılmaz bir platform. Bu API'yi oyluyo.com'da insanların oylamak istedikleri şeyleri kolayca bulabilmeleri için bir arama motoru olarak, eklenen maddelere otomatik olarak açıklama eklemek ve insanların oyladıkları şeyler ile ilgili daha fazla bilgi edinmelerini sağlayacak bilgileri çekmek için kullanıyoruz.




Örneğin, üstteki resimde açıklama ve Steffi Graf'ın fotoğrafı ve vatandaşlığına kadar tüm detayları otomatik olarak Wikidata API sayesinde çekiliyor.

Bu API'den pek faydalanılmadığını görmek beni üzdü. O yüzden API'den şöyle bir bahsetmek ve Wikidata'ya karşı ilgi uyandırmak istiyorum :) .

Wikidata'nın kendi sitesine girip herhangi birşey aratabilirsiniz ve sınıflandırılmış verileri tablolar halinde görebilirsiniz. Örneğin ben, favorim olan Inception filmini arattım:

https://www.wikidata.org/wiki/Q25188

Film ile ilgili mevcut bilgiler sitenin kullanııcı arayüzünde aşağıdaki gibi bize sunuluyor.


Tabiki maddelere programlarda kullanabileceğimiz JSON ve XML gibi formatlarda da erişebiliyoruz. Herhangi bir maddeyi sorgulatmak için wbgetentities action'ı ile sorgu yapıyoruz. Aynı yönetmen bilgisini JSON formatında almaya çalışınca da şöyle bir sonuç çıkıyor :))  https://www.wikidata.org/w/api.php?action=wbgetentities&ids=Q25188&languages=tr|en
Baya karmaşık ve anlamsız gibi görülen bu çıktı esneklik için tasarlanmış gibi. Bence bu kısım tüm wikidata yapısının bir özeti o yüzden bunu açıklayacağım gerisini İngilizce'yi iyi bilmiyor olsanız bile kavrarsınız gibime geliyor.
  
JSON çıktısını sırayla açıklamak gerekirse;

"P57" yönetmen(director) isimli özelliğin(property) ID'si. Bir maddenin özelliklerini almaya çalıştığımız zaman bize hep ID döner. Bu özelliğin Türkçe ya da İngilizce karşılığının ne olduğunu öğrenmek için ek bir sorgu göndermek gerekiyor.

"mainsnak" adlı objeler özelliğin değerini içerir. Tek yönetmen olduğu için P57 özelliğinin içerisinde sadece 1 mainsnak var ama örneğin başrolleri içeren özelliğe(cast member) bakarsanız çok fazla mainsnak içerdiğini göreceksiniz.

"datavalue" içerisindeki "numeric-id" ise örneğimizde yönetmenin id'sini verir örnekte Christopher Nolan'ın id'sini bize veriyor. API'yi kullanırken ID ile yine wbgetentities sorgusu yapıp "labels" kısmından sanatçının ismini almamız gerekecek: https://www.wikidata.org/w/api.php?action=wbgetentities&ids=Q25191&languages=tr|en

Şunu da söylemem lazım: Özellik değeri her zaman başka bir maddeye yönlendiren id olmayabiliyor. Tarih veya link gibi değerler de olabiliyor. Yazacağınız algoritmada buna önem vermeniz gerek :)  

wbgetentities action'ı id'sini bildiğimiz maddelerin özelliklerini öğrenmek için var. Tabi bunun yanı sıra wikipedia pageid'sini de bize sunuyor ve bu sayede -eğer varsa- maddenin Wikipedia'daki Türkçe açıklamasına da erişmiş oluyoruz. 

Wikidata veritabanında madde aratmak istiyorsak wbsearchentities action'ını kullanmamız gerekiyor.

Wikidata'nın en büyük problemlerinden biri Türkçe desteğinin sınırlı olması. Neyse ki genelde şehir, sanatçı gibi özel isimleri aldığım ve maddelerin Wikipedia linklerinin de sunulduğu için çok önem arz etmedi. Yine de Özellikle Türkçe Wikipedia sayfası olmayan maddeler için ihtiyaç oluyor ve onun için de Yandex Translate API'yi kullanıyorum. 

Bu yazıda sadece wbsearchentities ve wbgetentities'den bahsettim ama bu servisin onlarca farklı fonksiyonu da var. Resmi dokümantasyonundan bunlara erişebilirsiniz : https://www.wikidata.org/w/api.php

Wikidata'daki maddelerin wikipedia ansiklopedisinde bulunan açıklamalarını ve resimlerini almaya ihtiyaç duyarsanız kardeş proje olan Mediawiki'nin servisleri işinize yarayacak. https://www.mediawiki.org/wiki/API:Main_page





2 Şubat 2016 Salı

Websocket protokolü ile binary veri transferi


HTML5 ile yapılan gerçek zamanlı uygulamalar gittikçe artıyor. Websocket protokolü bu uygulamalarda server-client iletişimini sağlayan vazgeçilmez bir araç. Veri akışının çok fazla olduğu bu tarz sistemlerde gecikmeyi ve bandwith'i asgariye indirmek için gönderilen verinin optimize edilmesi gerekir.

JSON

Böyle sistemlerde insanlar tarafından kolayca okunabilmek için tasarlanmış JSON gibi formatlar verimsiz kalacaktır. Bunun nedenini bir multiplayer oyun örneği ile açıklayayım, tüm kullanıcılara saniyede yaklaşık 30 kere yollanan genel durum bilgisi aşağıdaki gibi JSON formatında olsun:
[{"id":2,"point":500,"x":55.31234535,"y":32.312332},{"id":3,"point":3000,"x":3.34261345,"y":22.52112362}]
Üstteki JSON 106 Byte boyutunda. Şimdi, boyutunu düşürmek için detayları azaltarak biraz anlamsızlaştıralım.
[[2,500,55.31234535,32.312332],[3,3000,3.34261345,22.52112362]]
Parametre isimlerini yok sayarak boyutu 63 Byte'a düşürebildik. Ama 4 tam ve 4 ondalıklı sayıyı gönderebilmek için bu kadar yer harcamak hala büyük bir sıkıntı, çünkü muhtemelen pozisyon bilgisi saniyede en az 25 defa yollanacak ve kullanıcı sayısı 2'den çok daha fazla olacak.

Bilgiyi bu şekilde string tipinde yolladığımız zaman her karakter en az 1 byte yer kaplar. Bundan dolayı örneğin id'si 2 olan oyuncunun x pozisyonu  11 byte yer kaplıyor. Bu pozisyon bilgisini float32 tipinde yollayabilseydik sadece 4 byte yer kaplayacaktı.

Binary veri transferi

Pozisyon bilgilerini float32 tipi ile tutarsak kullanıcı başına x ve y toplam 8 byte yer kaplar. ID ve puanı da int16 tipi ile tutalım onlarda toplamda 4 byte'tır. Bu hesaba göre kişi başına 12 byte ile istediğimiz bilgileri gönderebileceğiz. Yani, üstteki örnekteki iki kişinin bilgisini 24 byte'a göndermiş olacağız. Peki, bunu Javascript ile nasıl başarırız?

Javascript'te binary dizilerini oluşturmak ve görüntülemek için işe yarar sınıflar var. Örneğin binary veri dizisini temsil etmek için ArrayBuffer nesnesi kullanılır. ArrayBuffer 'a veriler Typed Array'lar aracılığıyla eklenir. Typed Array'lar binary veri oluşturmayı ve binary veriye erişmeyi sağlarlar. Gelin bahsettiğim sınıfları kullanarak örnekteki durumu gerçekleştirelim:
var players = [
  {id: 2, point: 50, x:55.31234535, y: 32.312332},
  {id: 3, point: 100, x:3.34261345, y: 22.52112362}
];
var buf = new ArrayBuffer(12*players.length);
players.forEach(function(player, index){
    var info = new Uint16Array(buf, index*12, 2);
    info.set([player.id, player.point], 0);
    var position = new Float32Array(buf, index*12+4, 2);
    position.set([player.x, player.y]);
});
ws.send(buf);

Yukarıdaki kod bloğu ArrayBuffer nesnesini oluşturduktan sonra kullanıcıların id ve puan bilgisi int16, pozisyonları ise float32 Typed Array nesneleri yardımıyla ArrayBuffer'a ekliyor ve son olarak ArrayBuffer nesnesini websocket ile client'a gönderiyor.

Server binary veriyi gönderdi... Peki client nasıl bu veriyi okuyacak ? Javascript'te bunun için DataView adlı sınıf mevcut. ArrayBuffer'a veriyi nasıl koyduysak DataView ile aynı şekilde geri alıyoruz.

var ws = new WebSocket('wss://example.com/socket');
ws.binaryType = "arraybuffer";
ws.onmessage = function(msg) {
 var players = [];
  if(msg.data instanceof ArrayBuffer) {
       var dv = new DataView(msg.data);
       for(var i = 0; i < dv.byteLength / 12; i++) {
        var player = {};
          var player.id = dv.getUint16(0);
          var player.point = dv.getUint16(2);
          var player.positionX = dv.getFloat32(4);
          var player.positionY = dv.getFloat32(8);
        players[i] = player;
       }
  }
}

Yukarıda client, server'da bulunan players dizisini, server'dan aldığı bilgiyle tekrar oluşturdu.

Böylece gönderilen binary verilerin nasıl alınacağını da görmüş olduk. Bir dahaki yazımda websocket protokolündeki ping pong sinyallerinden(heartbeat messages) bahsetmeyi düşünüyorum. O zamana kadar hoşçakalın :)

22 Ağustos 2015 Cumartesi

Cordova Uygulama boyutunu düşürme

Uygulamanızın çok boyut kaplayan ve apk'yı büyüten ek dosyalarını ( assets ) uygulama indikten sonra yükletebilirsiniz.

İlk adım ek dosyalarınızı zipleyip server'a kopyalamak. İkinci adım ise uygulama tarafında başlangıçta kontrollerin yapılıp ek dosyalar indirilmediyse indirilmesini başlatmak.

Bu iş için 2 plugine ihtiyaç var:

$ cordova plugin add cordova-plugin-zip
$ cordova plugin add cordova-plugin-file-transfer

İlk plugini zip dosyalarını çıkartması, ikinci plugini dosya transferini sağlaması için kullanacağız.


Bu iki plugini kurduktan sonra, sırada uygulama tarafında deviceready olayına bir listener atamak ve dosya bilgilerini gireceğimiz değişkenleri tanımlamak var.

// ek dosya ya da klasörün kopyalanacağı dosya yolu
var filePath = "/sdcard/";
            
//İndirelecek dosyanın URL yolu
var zipURL = "http://www.site.com/assets.zip";
            
//İndirilen dosyanın alacağı isim.
var fileName = "assets.zip";

document.addEventListener("deviceready", init, false);

init metodu assets'in inip inmediğini kontrol edip inmediyse indirilmesini indiyse uygulamanın başlatılmasını sağlar.
function init(){
               
    // eğer indirilmediyse..
    if(localStorage.getItem('downloaded') != "yes") {
        // zip dosyasını indir
        downloadZip();
                    
    } else {
        // uygulamayı başlatan metod
        appReady();
    }      
            
}

downloadZip metodu ise zip dosyasını indirip filePath değişkeniyle belirtilen dosya yoluna dosyaları aktarır.
function downloadZip() {
    var options = new FileUploadOptions();
    var fileTransfer = new FileTransfer();

    fileTransfer.download(
        encodeURI(zipURL),
        filePath + fileName,
        function(entry) {
            zip.unzip(filePath + fileName, filePath, appReady, null);
            console.log("download complete: " + entry.fullPath);
        },
        function(error) {
            console.log(error);
            console.log("download error source " + error.source);
            console.log("download error target " + error.target);
            console.log("upload error code" + error.code);
        },
        false, {

        }
    );

}

Zip dosyası indirilip çıkartıldıktan sonra uygulamayı başlattığını varsaydığım appReady metodu çağrılıyor. Sonraki açılışlarda assets'in tekrar indirilmesini engellemek için metot şu şekilde olmalı:
function appReady() {
    localStorage.setItem('downloaded', 'yes');

    // Uygulama başlatan kodlar.....
}

İndirilme sırasında progressbar'da gösterilebilir. Bunun için şu linke göz atabilirsiniz.

21 Ağustos 2015 Cuma

CodeIgniter & Nginx konfigürasyonu


Bu yazıda Nginx Server ve CodeIgniter framework'ü hakkında görüşlerimi ve konfigürasyon ayarlarlarını paylaşacağım.

Nginx?

Nginx yüksek eş zamanlılığa(concurrency) ve düşük hafıza tüketimine odaklanan bir web server'idir. Özellikle işlem hızı ve çok sayıda bağlantıyla başa çıkma yeteneği gerektiği zamanlarda Nginx ideal bir seçenek olarak önümüze çıkar.


CodeIgniter?

CodeIgniter'a gelecek olursak, yüksek performanslı, düşük ayakizine(hafıza kullanımı) sahip  tatmin edici bir dökümantasyona sahip olan PHP web framework'üdür.


İçinde bulunduğum son projede bu iki teknolojiyi tercih ettim. Kullanma sebeplerimi sayacak olursam:
  • Üzerinde çalıştığımız mobil uygulamanın yüksek performansa sahip bir web servise ihtiyaç duyması
  • Bağımlılığı minimum olan bir framework'e ihtiyaç duymam (PEAR ve benzeri büyük ölçekli kütüphaneler olmaksızın PHP5.4+ yüklü her sunucuda çalışacak şekilde olması)
  • Web servisin yanında mobil uygulama verilerinin yönetimi ve monitör edilmesini sağlayacak bir yönetim panelini hızlıca yapmamı sağlaması

Özellikle 3. seçenek slim gibi bir micro framework kullanmama sebebim sayılabilir.

Kurulum

Nginx ve PHP

Nginx ve PHP kurulumunu henüz yapmadıysanız bu makaleyi okumanızı öneririm.

CodeIgniter

CodeIgniter kurulumu çok kolay! Son versiyonunu(3.0.1) resmi websitesinden indirip server'inize kopyalamanız yeterli.

Konfigürasyon

Nginx

Nginx, Apache'deki Virtual Host mantığında çalışan server blokları kullanır. Server bloklarını websitenizin tarifini yapan dosyalar olarak görebilirsiniz.

Varsayılan olarak nginx websitenin tanımının yapıldığı server blokları
etc/nginx/sites-available/ yolunda bulunur. Bu klasör default dosyasına sahiptir.  Bu dosya bir website ile ilgili tüm gerekli bilgileri bulundurur.

Şimdi default adlı dosyaya girip CodeIgniter kullanan websitemiz için gerekli konfigürasyonu yapalım. 

server {
        #server'in dinleyeceği port
        listen       80;

        #server'in hizmet vereceği adres bu örnekte http://localhost
        server_name  localhost;

        #CodeIgniter projenizin adresi
        root   /var/www/html/ci;
        autoindex on;
        index index.php;
 
        location / {
 
           try_files $uri $uri/ /index.php;
 
           location = /index.php {
 
              fastcgi_pass   127.0.0.1:6969;
              fastcgi_param  SCRIPT_FILENAME /var/www/html/ci$fastcgi_script_name;
              include        fastcgi_params;
           }
        }
 
        location ~ \.php$ {
            return 444;
        }
}

Dosyayı kaydettikten sonra ayarları devreye sokmak için aşağıdaki komutu terminalden çalıştırıyoruz:

$ sudo service nginx restart

CodeIgniter

Son olarak application/config/config.php 'yi aşağıdaki gibi düzenliyoruz:

...

$config['base_url'] = "";
$config['index_page']  = "";
$config['uri_protocol'] = "AUTO";

...


Evet kurulum bu kadar. :)  İlerleyen yazılarda bu projede kullandığım kütüphanelerden bahsetmeyi planlıyorum.

Sağlıcakla kalın.

20 Temmuz 2014 Pazar

Cordova/Phonegap ile Ekran görüntüsü almak

Bu yazıda Cordova ile uygulamanın ekran görüntüsünü almak için kullandığım bir plugini anlatacağım.

Kullanımı basit, ilk önce projemize ekleyelim.
$ cordova plugin add https://github.com/gitawego/cordova-screenshot

Kullanımı


Plugin save ve URI metodlarından oluşuyor.

save

navigator.screenshot.save(function(error,res){
  if(error){
    console.error(error);
  }else{
    console.log('dosya yolu: ',res.filePath);
  }
});

Bu metoda 2 parametre alan callback fonksiyon göndermek ekran görüntüsünü alabilmek için yeterli. İlk parametre eğer hata oluşmuşsa onu gösterir, ikincisi de sonucu döner. Dosya yolunu res.filePath  şeklinde alabiliyoruz.

Resimler android için /sdcart/Pictures dizinine kaydediliyor.

Callback fonksiyonun yanında kaydedilecek dosya türü , çözünürlük kalitesi ve dosya ismi  değerlerini de gönderebiliriz.

navigator.screenshot.save(function(error,res){
  if(error){
    console.error(error);
  }else{
    console.log('dosya yolu: ',res.filePath);
  }
},'jpg',50,'resimAdi');

Bu metodu ios ve android de kullanabiliyoruz.

URI

Her zaman ekran görüntüsünü telefona kaydetmek istemeyebilirsiniz.Sadece data URI olarak alıp öyle kullanmanız gerekli olabilir. Bunu da plugine eklediğim URI metodu ile yapıyoruz.


navigator.screenshot.URI(function(error,res){
  if(error){
    console.error(error);
  }else{
    html = '<img src="'+res.URI+'" style="width: 50%;">';
    document.body.innerHTML = html;
  }
},50);

URI metodu bir callback fonksiyonu ve  kalite değerini alıyor. Bize gelen res.URI resim verisini img etiketi ile kullanıcıya gösterebileceğimiz gibi, server'a da bir string değer yolluyormuşuz gibi de yollayabiliriz.

Bu metodu ise şimdilik sadece android de kullanabiliyoruz. Umarım yakın zamanda ios için de implement edecek biri çıkar.

12 Temmuz 2014 Cumartesi

Cordova/Phonegap ile Sqlite3 veritabanı işlemleri

Bir önceki yazıda sqlite veritabanına bağlanmayı anlatmıştım.

Kullandığımız SQLitePlugin, yapı olarak HTML5 SQL API(web sql)  ile birebir aynı olmayı amaçlamış. Tek büyük fark ise veritabanının açılış şekli gibi gözüküyor (window.openDatabase() yerine window.sqlitePlugin.openDatabase() kullanıyoruz.) .

HTML5 SQL API'de dolayısıyla SQLitePlugin'de 3 ana metod bulunmakta.

  1. openDatabase
  2. transaction
  3. executeSql

openDatabase

Bir önceki yazı da openDatabase metodunu kullanarak veritabanını açmıştık. Aslında veritabanını açmak için 2 seçeneğimiz bulunuyor. İlki bir önceki yazıda da kullandığımız ve önerilen yöntem:

  var db = window.sqlitePlugin.openDatabase({name: "databaseAdi.db"});

Birde klasik yöntem var:

   
  var db = window.sqlitePlugin.openDatabase("databaseAdi.db", "1.0", 
                                          "Deneme veritabanı", 2*1024);

Method 4 parametre alıyor:

  1. Veritabanı adı
  2. Versiyon numarası
  3. Açıklama metni
  4. Tahmini veritabanı boyutu

 Özellikle web sql kullanırken 2. yöntemi kullanmak isteyebilirsiniz. Ama SQLitePlugin kullanırken bu kadar detaya gerek kalmıyor.

Veritabanını açmış bulunmaktayız.Burada önemli nokta ise, bu metodu deviceReady olayından sonra çağırmak. Aksi takdir de uygulamanız hata verecektir.

Transactions(İşlemler)

Veritabanımızı açtık. Artık sorgu yazmak veri almak istiyoruz.. Fakat bu sorgularımızı transaction içerisinde yazmamız gerekiyor. Transaction aslında işlem demek. Sorgularımızı işlem altında yapıyoruz  çünkü işlemler bize geri alma yeteneği kazandırıyor. Bu şu demek: Eğer bir işlem içindeki bir yada birkaç sql sorgusu başarısız olursa ( sql sorgusu yada  herhangi bir kod) o işlem altında veritabanına yapılan güncellemeler iptal edilir. Yani, sanki işlem(transaction) hiç çalışmamış gibi olur. Bunun yanında oluşan hatayı da yakalayabiliriz.

Örneğe bakalım:

  var db = window.sqlitePlugin.openDatabase({name: "databaseAdi.db"});

  db.transaction(function (tx) {
    // Burada işlemler..
    // tx nesnesini kullanarak sql sorguları yapıyoruuuz..
  },function(e) {
    console.log("HATA: " + e.message);
  });

transaction metoduna 2 fonksiyon yolladım gördüğünüz gibi. Biri sql sorgularımızın olacağı fonksiyon, diğeri ise eğer hata oluşursa çalışacak ve hatayı işlememizi sağlayacak diğer bir fonksiyon.

İlk fonksiyon tx adlı bir nesne alıyor. Bu nesne ile beraber artık sql sorgu çalıştırmaya hazırız.

executeSql

executeSql metodu pek çok işimize yarıyor. Bu metodla istediğimiz sql sorgularını yapabiliyoruz, bizi sql injection'a karşı koruyor ve sorgu sonucunu işlemek için bir de callback sağlıyor.

Bir önceki örneği biraz değiştirelim:

   var db = window.sqlitePlugin.openDatabase({name: "databaseAdi.db"});

  db.transaction(function (tx) {
   tx.executeSql("CREATE TABLE kisi (id UNIQUE,ad TEXT)");
   
   tx.executeSql("INSERT INTO kisi VALUES(1,"Halil")");
  });

transaction içerisinde kisi adlı tablo oluşturduk ve içerisine 1 adet veri ekledik. Ama şuanki haliyle adı veya id'yi farklı bir kaynaktan çekmeye çalışırsak (input, hash vs..) sql injection'a davetiye çıkarmış oluruz değil mi ?

Gelin son olarak, hem bu sorunu çözelim hem de eklediğimiz satırı ayrı bir sorguyla alıp işlemeye çalışalım.

  var db = window.sqlitePlugin.openDatabase({name: "databaseAdi.db"});

  db.transaction(function (tx) {
    tx.executeSql("CREATE TABLE kisi (id UNIQUE,ad TEXT)");
   
    tx.executeSql("INSERT INTO kisi VALUES(?,?)",[1,"Halil"]);

    tx.executeSql("SELECT * FROM kisi",[], function(tx, res){
      
      console.log("Toplam çekilen satır sayısı: "+ res.rows.length);
    
      // çekilen satırlardan (şuan bir satır olması gerekiyor gerçi) 
      // ilk satırı alıyoruz
      kisi = res.rows.item(0);
 
      console.log("Kullanıcı adı: " + kisi.ad + " Id'si : " + kisi.id ); 
    });
  });

Örnekte de gördüğünüz gibi SELECT sorgusuyla çektiğimiz verilere ulaşmak çok kolay. executeSql metodunun bize sağladığı 2. argüman olan res ile satırlara erişebiliyoruz. Aynı zaman da veritabanına ekleme yapmak için çağırdığımız executeSql metoduna da bir callback ekleyip res parametresiyle kaç satır etkilendiğini kontrol etmemizi sağlayan res.rowsAffected ve eğer tabloda otomatik artan (auto_increment) bir id var ise eklenen yeni satırın id'sine res.insertId şeklinde erişmemiz mümkün.

Bu yazılık bu kadar. Daha fazla bilgi için aşağıdaki kaynaklara göz atabilirsiniz .

Kaynak : http://html5doctor.com/introducing-web-sql-databases/
              https://github.com/brodysoft/Cordova-SQLitePlugin/blob/master/README.md



5 Temmuz 2014 Cumartesi

Cordova/Phonegap ile Sqlite3 veritabanına bağlanmak

Mevcut sqlite3 veritabanınızı Cordova projenize eklemek varolan pluginleri kullanarak çok kolay bir hal almış.

Hemen anlatayım:

İlk sqlite pluginimizi indiriyoruz (Projenizin olduğu klasör üzerindesiniz varsayıyorum)
$ cordova plugin add https://github.com/brodysoft/Cordova-SQLitePlugin
Maalesef bu yetmiyor, mevcut veritabanınızı uygulama klasörüne kopyalayacak bir plugine daha ihtiyacımız var.
$ cordova plugin add https://github.com/an-rahulpandey/cordova-plugin-dbcopy

Android için veritabanınızı PROJE/platforms/android/assets klasörüne kopyalayın.

IOS için ise Resource klasörüne kopyalayın ve veritabanını Xcode Projenize ekleyin.(Resources klasörüne sağ tık-> Add Files)

Şimdi, deviceready olayına bir dinleyici bağlayacağız.

var db;
document.addEventListener("deviceready", function(){
   function dbcopy()
   {
      // Veritabanını Uygulama Dizinine kopyalar
      // Başarılı olursa openDB fonksiyonunu çağıracak.
      window.plugins.sqlDB.copy("database.db",openDB);
   }

   function openDB()
   {
      db = window.sqlitePlugin.openDatabase({name: "database"});
   }

   if(! window.localStorage.getItem('dbCopied') )
   {
      window.localStorage.setItem('dbCopied',true)
      dbcopy();
   }else
   {
      openDB();
   }
}, false);

Veritabanı adının database.db olduğunu varsaydım, dosya uzantısı .db olmak zorunda , çünkü sqlite plugini öye istiyor. :)

Sonda ise eğer bir kere uygulama dizinine kopyaladıysa, bir daha boşyere kopyalamaya çalışmasın diye bir kontrol yaptık.

Bu yayınlık bu kadar, bir sonraki yayında, javascript üzerinden basit veritabanı işlemleri yapacağız.