iOS’ta Dosya Depolama ve Paylaşma
iOS ve Windows arasında, çoğu kodların aynı olmasına rağmen, temel bir fark vardır: iOS’taki dosyalar kum havuzu / sandbox korumasındadır. Sadece “Belgelerim”deki bir dosyayı açıp, diskin başka bir yerine kaydedemezsiniz. Aslında, uygulamanızın bulunduğu dizin dışındaki herhangi bir dosyaya ulaşamazsınız. Kum havuzu ile nasıl baş edileceğini bu yazının kalan kısmında ele alacağız.
Belge Kum havuzu
Windows’ta çalışırken, uygulamalar sabit diskin neredeyse her yerine ulaşabilir. Bu da kullanışlılık açısından iyi bir şey olmasına rağmen güvenlik açısından da bir kabustur. Düşünün ki internetten bir uygulama indiriyorsunuz. Bunun sabit diskinizdeki tüm belgeleri şifreleyip, kurtarmak için de fidye ödemesi istenmesini nasıl engelleyebilirsiniz?
iOS’ta ise, uygulamanız sadece yüklendiği dizin ve bunun altdizinlerinde okuma yazma yapabilir. Bu özellik uygulamanızı kaldırdığınızda, diskinizde hiç çöp bırakmadan tamamen temizlenmesini sağlar. Diğer taraftan böyle bir engelleme ile nasıl çalışacaksınız? Örneğin (Flexcel) uygulamanız ile Excel birbirini görmezken, Excel’de oluşturduğunuz bir dosyayı uygulamanız ile nasıl açıp düzenleyip yeni değerler ile tekrar Excel’e geri göndereceksiniz?
Dosya paylaşma
İlk yol özel dosyalardır: Uygulamalar adres defteri verileri ve resimler gibi bazı diğer dosyalara ulaşabilir, fakat sadece özellikle o amaçla tasarlanmış özel API’ler aracılığı ile. Üstelik bu genel bir çözüm olmayıp, resimlerle çalışsa da, xlsx veya PDF gibi dosyalarla çalışmaz.
Dosyalar için daha iyi çözüm 2 kısımda gelmektedir:
Uygulamanız için bazı ulaşılabilir dizinlere bakış
Devam etmeden ve kabullenmeden önce bilmelisiniz ki cihazdaki herhangi bir dizine yazamazsınız. O halde okuyup yazabileceğiniz dizinlere bakalım:
Diğer Uygulamalardan Dosyaları İçe Alma (Import)
Uygulamanızı iOS’a kaydetme
Diğer uygulamalardan gelen dosyalarla uğraşmak için, uygulamanızı ilgili dosya uzantılarını yakalabilecek bir program olarak kaydemeniz gereklidir. Bunun için de, uygulama paketinizdeki Info.plist’i düzenlemelisiniz.
Örneğin xls veya xlsx dosyaları için, aşağıdakileri Info.plist’e eklemelisiniz:
Fakat ne yazık ki sadece basit türdeki string anahtarları eklememize izin vermektedir ve uzun sözlükleri bizim eklememiz gerekmektedir. O halde hazır gelen sistemi kullanamayız.
Bir dosya yakalayıcısı kaydetmek için, basit anahtar ekleme yerine daha karmaşık olan sözlük eklememiz gerekmektedir. Bu da bu yazının yazıldığı vakitte Delphi’de (11 sürümü) dahili olarak bulunmadığı için fazladan bir emek harcamayı gerektirmektedir.
(FlexCel bileşeni infoplist.exe adlı yardımcı uygulaması aracılığı ile iki xml dosyasını derleme sonrasında çalıştırıp içe alma bu yazı muhteviyatına alınmadı. Uygulamanızı adım adım nasıl kaydedeceğinizi iOS tutorial altında bulabilirsiniz.)
Herşey ayarlandıysa uygulamanız telefonun diğer uygulamaları tarafından “Open in” diyalogunda görüntülenir.
“Open in” olayını cevaplamak
Uygulamanızı xlsx dosyalarını yakalayan bir uyg.olarak kaydettiğinizde, diğer uygulamaların “Open in” dialoglarında görüntülenecektir. Kullanıcı uygulamanızın simgesine tıkladığında da iOS dosyayı <Uygulamanızın dizini>/Documents/Inbox dizini altına kopyalacaktır (Bkz “A look at some of the available folders for your application”).
iOS uygulamanızı başlattıktan ve ona application:OpenUrl: iletisi gönderdiktan sonra, uygulamayı ancak açabilirsiniz. O halde bir şeyler yapmak için, application:OpenUrl: olayını dinlemeniz gerekmektedir.
Delphi’de aşağıdaki komutlar ile bu olayı dinleyebilirsiniz:
Başlatma kodu: (Formunuzun Create olayına ya da projenizin initialization kısmına ekleyiniz)
Olay yakalama:
Not: AppHandler fonksiyonu OpenURL üzerinden yakalanan dosyanın tam adı yerine (“file://localhost/folder...” gibi) URL bilgisini gönderir.
Diğer uygulamalardan gelen dosyayı okuma:
OpenURL içinde URL’i bilinen dosya üzerinde okuma işlemi yapabilirsiniz:
iOS’ta dosyanın URL’sini elde ediyoruz, dosya adını değil. Örneğin, alınan URL şöyledir: 'file://localhost/private/var/mobile/Applications/9D16227A-CB01-465D-B8F4-AC43D70C8461/Documents/Inbox/test.xlsx'
Halbuki asıl dosya adı şöyle olmalıdır: ‘/private/var/mobile/Applications/9D16227A-CB01-465D-B8F4-AC43D70C8461/Documents/Inbox/test.xlsx’
iOS metodları normal olarak URL veya yol kullanır. Delphi’nin TFileStream ise yol ile çalışır. Bu yüzden URL’i GetPhysicalPath fonksiyonunu kullanarak yol olarak çevirmeliyiz.
Delphi 10.4 ve üstünde mobil platformlar ARC’ye sahip değil, demek ki artık “Free”yi çağırmak zorundasınız. Win32 için tüm nesneleri “free” yapmalısınız.
Dosyaları yedekleme:
Dosyaları kullanmak hakkında bir not: Dosyaların tümünü yedekleme gerekmemektedir ve uygulamanızın statik dosyaları yedeklemesini (yedekleme süresini ve boyutunu artırdığı için) App Store red sebebi olarak kabul etmektedir.
xls veya xlsx dosyalarını uygulamanız için şablon oarak kullanıyorsanız ve bunlar gerçekte lazım olan bilgi olmayıp yedeklemeniz gerekmiyorsa, NSURLIsExcludedFromBackupKey veya kCFURLIsExcludedFromBackupKey özelliklerini kullanıp yedeklemeden ayrı tutmak için kullanmalısınız.
Daha fazla bilgi için bkz: https://developer.apple.com/library/ios/#qa/qa1719/_index.html
Dosya paylaşma için diğer yollar
Dosyaları dışa verme ve içe alma yanında, uygulamanıza dosya alıp vermenin iki yolu daha mevcuttur:
iTunes ile dosya paylaşma
Uygulamanız “iTunes ile paylaş” özelliğini de sunabilir. Açmak için Info.plist dosyasına şu anahtarı ilave edin:
Not: Tekrar belirtelim ki bazı dosya tipleri için uygulamayı kaydetme durumunda, Delphi IDE’si doğrudan bunu direk olarak izin vermez. Bir Boolean anahtar eklemelisiniz, fakat Delphi sadece string anahtarlara izin vermekte. O halde yine “Uygulamanızı iOS’a kaydetme” konusunda bahsedildiği gibi farklı bir Info.plist oluşturup birleştirmelisiniz. Önceden içe alma için dosya kaydetme yaptıysanız, aynı dosyayı bu giriş için kullanabilirsiniz.
İkaz: Uygulamanız için iTunes ile dosya paylaşmayı açtıysanız, “Documents” dizinindeki dosyalar kullanıcının gerçekten ihtiyacı duyacakları olduğuna emin olun ve diğerlerini başka bir yere mesela “Library” dizinine koyun. Böyle yapmamak App store reddine sebep olabilir. (Bkz: http://stackoverflow.com/questions/10767517/rejected-by-uifilesharingenabled-key-set-to-true )
Project > Deployment
Uygulamanıza dosya vermenin son yolu, Delphi’deki “Menu->Project->Deployment” seçeneğidir.
Tabii ki sadece uygulama paketiniz ile dosya alabilirsiniz, dosyaları doğrudan “Documents” dizinine koyamazsınız. Zira Documents dizinini App store’a yükleyemezsiniz, sadece uygulama paketi yüklenir.
Uygulamanızı “MyApp” olarak adlandırırsanız dizin yapısı şu şekildedir:
Dosyaları sadece şekildeki yeşil dizinlere koyabilirsiniz. Nitekim uygulamanız da App store tarafından dağıtılmaktadır, uygulamayı indiren kullanıcılar da sadece uygulamanızla birlikte gelenlere ulaşılabilecektir.
Öyleyse dağıtım paketimizdeki dosyaları mavi dizinlere nasıl koyacağız? Sıradan teknik iOS’un onları MyApp.app’ın içindeki bazı dizinlere koyması ve uygulamanız başlarken dosyaları “/Documents” veya “/Library”e kopyalamadır.
Delphi bu kabiliyete sahip olduğundan başlatmada dosyaların kopyalamasından endişe etmenize lüzum yoktur. Proje kaynağınıza baktığınızda (menü > “View source”), kodun şöyle olduğunu görebilirsiniz:
Demek ki, “/Documents”e yerleştirmek isterseniz, onun yerine “StartUp/Documents”e yerleştirmelisiniz. “/Library”e yerleştirmek için de, “StartUp/Library”e yerleştirmelisiniz, v.b. Dosyalar uygulama paketiniz içinde kopyalanacak ve sonra da uygulamanız başlatıldığında ana dizine kopyalanacaktır.
Mühim: Cihazlardaki dosya adları büyük-küçük harf duyarlıdır. Tam olarak “StartUp/Documents”a yerleştirmelisiniz. Mesela “Startup/Documents”a yerleştirirseniz, o dosyalar Uygulamanız.App/Startup/Documents içine yerleştirilecektir, Delphi de uygulamanız başladığında onları /Documents içine kopyalayamayacaktır.
* Kaynak:
TMS Software FlexCel iOS Guide https://doc.tmssoftware.com/flexcel/vcl/...guide.html
iOS Tutorial https://doc.tmssoftware.com/flexcel/vcl/...orial.html
** Çevirenin notu: Yazıdakinin aksine iOS “/StartUp/” altındaki dosyaları da uygulama dizini yani kum havuzu altına koymaktadır.
Yukarıda info.plist dosyasının oluşturulması için (FlexCel bileşenine özel) kullanamayacağımız bir yol anlatılmış olup, yazıdan çıkarılmıştır. Bunun yerine bu işi elle yapmalıyız.
İçe alınacak dosya türü kaydı adımları:
1. İçe alınacak bir dosya uzantısı belirleyiniz. Örneğin: .dnm, .xls, .xlsx, .sheet, .txt, …
2. info.plist.TemplateiOS.xml dosyasını açınız.
3. Mevcut satırlar olan
4. Buradaki bilgileri ihtiyacınıza göre düzenlemesiniz.
CFBundleDocumentTypes: CFBundle yazılım paketi tarafından desteklenen belge tipleridir. https://developer.apple.com/documentatio...umenttypes
CFBundle: Görüntüler, sesler, yerelleştirilmiş dizeler ve yürütülebilir kod dahil olmak üzere birçok türde uygulama kaynağını düzenlemek ve bulmak için paket adı verilen bir dizin hiyerarşisi kullanmanıza olanak tanır. macOS'ta paketler, Mach-O çerçevelerinden işlevleri yüklemek ve yürütmek için CFM uygulamaları tarafından da kullanılabilir. Birden çok dili desteklemek veya uygulamanızı birden çok işletim ortamında yürütmek için paketleri kullanabilirsiniz.
CFM: Code Fragment Manager MacOS bellek yönetim sistemidir. Carbon uygulamalarının Mac'te çalışan uygulamalardan gelen sistem çağrılarını işlemekten sorumludur.
LS Launch Services: Geçerli uygulama işleminizden diğer uygulamalardaki belgeleri başlatır ve açar. https://developer.apple.com/documentatio...h_services
UTExportedTypeDeclarations: Uniform Type Identifiers uygulamanın sahibi olduğu ve uygulama tarafından dışa verilebilen tekdüzen tip tanımlayıcılarıdır. https://developer.apple.com/documentatio...clarations https://developer.apple.com/library/arch...fiers.html
UTI Uniform Type Identifiers çerçevesi: MIME ve dosya türleriyle eşlenen yaygın türlerin bir koleksiyonunu sağlar. Uygulamanızdaki dosya türlerini açıklamak için projenizde bu türleri kullanın. Bu açıklamalar, sistemin aktarım için dosya depolama biçimlerini veya bellek içi verileri düzgün bir şekilde işlemesine yardımcı olur; örneğin, çalışma alanına veya çalışma alanından veri aktarımı. Tanımlayıcı türleri, dizinler, birimler veya paketler gibi diğer kaynakları da tanımlayabilir. https://developer.apple.com/documentatio...clarations
public.mime-type
https://mimetype.io/
CFBundleDocumentTypes
CFBundleTypeName: Dosya tipi hakkında tanımlama (iOSDosyaDepolamaPaylasma dosyasi, Excel document, …)
CFBundleTypeRole: Editor, Viewer, Shell, QLGenerator, None olabilir. Editor ile düzenleme yapılabilir. Viewer ile içe alınan dosya salt okunur olarak geçici olarak alınabilir.
LSHandlerRank: Owner, Default, Alternate, None olabilir. Owner çalışıyor.
LSItemContentTypes: <array><string></string></array> arasında bir ya da daha çok dosya türü tanımlanabilir. (com.delphican.iOSDosyaDepolamaPaylasma.dnm, com.microsoft.excel.xls, com.tms.flexcel.xlsx, org.openxmlformats.spreadsheetml.sheet)
UTExportedTypeDeclarations
UTTypeDescription: (Uzantı) tam dosya türü adı
UTTypeTagSpecification: Array türünde çok sayıda tanımlanabilir. public.filename-extension kullanılır.
public.filename-extension anahtarı altında belirlediğimiz İçe alınacak dosya uzantıları eklenir ( .dnm, .xls, .xlsx, .sheet, .txt, …)
UTTypeConformsTo: Array türünde çok sayıda tanımlanabilir. public.data (, public.database, …)
UTTypeIdentifier: com.şirket.uygulama.uzantı (com.delphican.iOSDosyaDepolamaPaylasma.dnm, com.tms.flexcel.xlsx, …)
5. Projenizin derleme sırasında ve iOSDevice64\Debug veya iOSDevice64\Release altında projeadı. info.plist dosyasını tetkik ediniz.
6. İçe alma işlemini iOS info.plist içindeki dosya türünü kullanarak halledecektir. “.dnm” uzantılı bir dosyayı eposta, Whatsapp, vb. bir uygulama ile cihazınıza gönderip test edebilirsiniz. Open in menüsünde uygulamanız gösterilmezse info.plist içindekiler hatalıdır.
Dosyaları Dışa Verme (Export) ve Paylaşma
Dosyaları diğer uygulamalar için dışa verme yukarıda gördüğümüz dosyaları içe almanın tersidir. Şimdi de kullanıcıya oluşturduğumuz dosyayı açabilecek tüm uygulamaları bir diyalog halinde göstermeliyiz.
iOS’ta dosyaları dışa vermek ve paylaşmak aynı şeydir. Dosya paylaşma arayüzünde kaydırma menüsünde “Kopyala, Yeni Hızlı Not, Dosyalara Kaydet, Etiket Ekle” seçenekleri gösterilmektedir. “Dosyalara Kaydet” seçip “Göz At” arayüzü ile Konumlar (iPhone’umda, iCloud Drive, İndirilenler) dizinlerinde dosya kaydedilebilmektedir. Bu dosyaları sonradan sadece kullanıcının kendisi Dosyalar uygulaması üzerinden ulaşabilmektedir. Bizim uygulamalarımız ise kendi kaydettikleri dosyalara yine ulaşamamaktadır.
Delphi örneklerindeki \Samples\Object Pascal\Mobile Snippets\ShareSheet projesi sadece kamera ile resim çekip paylaşma yeteneğini göstermektedir. Dosya dışa verme ve paylaşma kısmı bulunmamaktadır.
Avustralyalı Delphi Worlds topluluğu tarafından hazırlanan “Kastri“çoklu platform kütüphanesi, RAD Studio Delphi’nin bazı önemli eksik API’lerini tamamlamaktadır. “ShareItems” desteği Delphi’deki ShareSheet aksiyonlarının alternatifidir. Metin, resim ve dosyaların paylaşılmasını sağlamaktadır.
TShareItems üzerinden AddFile, AddImage veya AddText her biri çağırılarak paylaşılacak öğeler eklenebilir.
“Share” metodu ile önceden eklenmiş öğeler dışarıya verilip paylaşılabilir. iOS’un AExcludedActivities parametresini kullanarak paylaşılacak faaliyetleri sınırlayabilirsiniz. Bugün için bunlar:
Kaynak: https://github.com/DelphiWorlds/Kastri/t...ShareItems
“ShareItems” desteğini kullanmak için https://github.com/DelphiWorlds/Kastri sitesinden kod zip olarak indirilip,
Project > Options > Building > Delphi Compiler > Search path :
C:\Kastri-master\API;C:\Kastri-master\Core;C:\Kastri-master\Include;C:\Kastri-master\Features;C:\Kastri-master\Features\ShareItems
dizinleri kaydedilmelidir.
Başlatma kodu: (Formunuzun Create olayına ya da projenizin initialization kısmına ekleyiniz)
Apple Dosya Sistemi Programlama Rehberi https://developer.apple.com/library/arch...72-CH2-SW4
iOS’ta Dizinler - Delphi Fonksiyon Karşılıkları
GetHomePath: /private/var/mobile/Containers/Data/Application/D232D883-5618-42FB-AC55-84A26D4FEF10
GetDocumentsPath: /var/mobile/Containers/Data/Application/D232D883-5618-42FB-AC55-84A26D4FEF10/Documents
GetCachePath: /var/mobile/Containers/Data/Application/D232D883-5618-42FB-AC55-84A26D4FEF10/Library/Caches
GetLibraryPath: /var/mobile/Containers/Data/Application/D232D883-5618-42FB-AC55-84A26D4FEF10/Library
GetTempPath: /private/var/mobile/Containers/Data/Application/D232D883-5618-42FB-AC55-84A26D4FEF10/tmp
GetPublicPath:
GetPicturesPath:
GetCameraPath:
GetMusicPath:
GetMoviesPath:
GetAlarmsPath:
GetRingtonesPath:
GetDownloadsPath:
GetSharedDocumentsPath:
GetSharedDownloadsPath:
GetSharedCameraPath:
GetSharedAlarmsPath:
GetSharedPicturesPath:
GetSharedMusicPath:
GetSharedMoviesPath:
GetSharedRingTonesPath:
(Project > Deployment > Remote Path : \StartUp\Documents\ = GetDocumentsPath)
· Görüldüğü gibi sadece GetHomePath, GetDocumentsPath, GetCachePath, GetLibraryPath, GetTempPath dahili depolama dizinleri olup, bunlardaki dosyaları okuyabilmekteyiz. Diğer harici dizinler ise kum havuzu dışında olduğundan, ulaşılamayıp boş karşılık vermektedir. Sonuç olarak iOS’ta sadece Dahili Depolamaya sahibiz. Harici Depolamaya ulaşamıyoruz.
· Delphi 11.2 Architect Trial, MacOS 12 Monterey, iOS 16.1.1 kullanılmıştır. Bu arada AMD işlemcili bilgisayarlarda VirtualBox ile iOS uygulama yazmakta sıkıntı yok ama ayarlar uğraştırıyor. iPhone cihazı VirtualBox MacOS’un görmesi için Finder’ı açın. Usb kablosu ile bağlayıp Ayarlar > Hücresel > Hücresel Veri kapalı ise açın, Kişisel Erişim Noktası açın. İkaz sesi gelene kadar biraz bekleyin. Kişisel Erişim Noktasını kapatıp, yarım dakika kadar bekleyip cihazın Finder’da görüldüğünü tetkik edin. Daha sonra PAServer da açıksa ile Delphi iOS Device 64-bit yanında cihazınızı görebiliyorsunuz.
· “iOSDosyaDepolamaPaylasma” örnek projesinde dahili depolamaya kayıt, metin pdf resim Dışa verme paylaşma ve İçe dosya alma yakalama kodları bulunmaktadır. Hepimize faydalı olması dileği ile.
iOS ve Windows arasında, çoğu kodların aynı olmasına rağmen, temel bir fark vardır: iOS’taki dosyalar kum havuzu / sandbox korumasındadır. Sadece “Belgelerim”deki bir dosyayı açıp, diskin başka bir yerine kaydedemezsiniz. Aslında, uygulamanızın bulunduğu dizin dışındaki herhangi bir dosyaya ulaşamazsınız. Kum havuzu ile nasıl baş edileceğini bu yazının kalan kısmında ele alacağız.
Belge Kum havuzu
Windows’ta çalışırken, uygulamalar sabit diskin neredeyse her yerine ulaşabilir. Bu da kullanışlılık açısından iyi bir şey olmasına rağmen güvenlik açısından da bir kabustur. Düşünün ki internetten bir uygulama indiriyorsunuz. Bunun sabit diskinizdeki tüm belgeleri şifreleyip, kurtarmak için de fidye ödemesi istenmesini nasıl engelleyebilirsiniz?
iOS’ta ise, uygulamanız sadece yüklendiği dizin ve bunun altdizinlerinde okuma yazma yapabilir. Bu özellik uygulamanızı kaldırdığınızda, diskinizde hiç çöp bırakmadan tamamen temizlenmesini sağlar. Diğer taraftan böyle bir engelleme ile nasıl çalışacaksınız? Örneğin (Flexcel) uygulamanız ile Excel birbirini görmezken, Excel’de oluşturduğunuz bir dosyayı uygulamanız ile nasıl açıp düzenleyip yeni değerler ile tekrar Excel’e geri göndereceksiniz?
Dosya paylaşma
İlk yol özel dosyalardır: Uygulamalar adres defteri verileri ve resimler gibi bazı diğer dosyalara ulaşabilir, fakat sadece özellikle o amaçla tasarlanmış özel API’ler aracılığı ile. Üstelik bu genel bir çözüm olmayıp, resimlerle çalışsa da, xlsx veya PDF gibi dosyalarla çalışmaz.
Dosyalar için daha iyi çözüm 2 kısımda gelmektedir:
- xlsx, pdf, html gibi dosyalarlarınızdan daha fazla yararlanmak için, onları diğer uygulamalara Dışa ver / Export ile vermelisiniz.
- Dropbox veya eposta gibi diğer uygulamalardan dosya okuyabilmek için, dosyayı İçe al / Import ile almalısınız.
Uygulamanız için bazı ulaşılabilir dizinlere bakış
Devam etmeden ve kabullenmeden önce bilmelisiniz ki cihazdaki herhangi bir dizine yazamazsınız. O halde okuyup yazabileceğiniz dizinlere bakalım:
- <Uygulama_yeri>/Documents/ Burası normalde dosyalarınızı koyduğunuz yerdir. iTunes tarafından yedeklenir.
- < Uygulama_yeri >/Documents/Inbox Burası diğer uygulamaların sizinki ile paylaşmak için dışa verdiklerinde dosyaları koydukları yerdir. Salt okunur. iTunes tarafından yedeklenir.
- < Uygulama_yeri >/Library/ Burası uygulamanızla beraber gelen, fakat kullanıcı için olmayan dosyalar içindir. Örneğin xlsx şablonlarını buraya koyabilirsiniz.
- < Uygulama_yeri >/tmp/ Buraya yazdığınız dosyalar uygulamanız çalışmadığında silinebilir. iTunes tarafından yedeklenmez.
Diğer Uygulamalardan Dosyaları İçe Alma (Import)
Uygulamanızı iOS’a kaydetme
Diğer uygulamalardan gelen dosyalarla uğraşmak için, uygulamanızı ilgili dosya uzantılarını yakalabilecek bir program olarak kaydemeniz gereklidir. Bunun için de, uygulama paketinizdeki Info.plist’i düzenlemelisiniz.
Örneğin xls veya xlsx dosyaları için, aşağıdakileri Info.plist’e eklemelisiniz:
<dict> <key>CFBundleDocumentTypes</key> <array> <dict> <key>CFBundleTypeName</key> <string>Excel document</string> <key>CFBundleTypeRole</key> <string>Editor</string> <key>LSHandlerRank</key> <string>Owner</string> <key>LSItemContentTypes</key> <array> <string>com.microsoft.excel.xls</string> <string>com.tms.flexcel.xlsx</string> <string>org.openxmlformats.spreadsheetml.sheet</string> </array> </dict> </array> <key>UTExportedTypeDeclarations</key> <array> <dict> <key>UTTypeDescription</key> <string>Excel xlsx document</string> <key>UTTypeTagSpecification</key> <dict> <key>public.filename-extension</key> <string>xlsx</string> <key>public.mime-type</key> <string>application/vnd.openxmlformats-officedocument.spreadsheetml.sheet</string> </dict> <key>UTTypeConformsTo</key> <array> <string>public.data</string> </array> <key>UTTypeIdentifier</key> <string>com.tms.flexcel.xlsx</string> </dict> </array> </dict>Delphi project preferences altındaki “Version info” kısmında Info.plist’in her bir anahtarı değiştirebilmenizi sağlamaktadır
Fakat ne yazık ki sadece basit türdeki string anahtarları eklememize izin vermektedir ve uzun sözlükleri bizim eklememiz gerekmektedir. O halde hazır gelen sistemi kullanamayız.
Bir dosya yakalayıcısı kaydetmek için, basit anahtar ekleme yerine daha karmaşık olan sözlük eklememiz gerekmektedir. Bu da bu yazının yazıldığı vakitte Delphi’de (11 sürümü) dahili olarak bulunmadığı için fazladan bir emek harcamayı gerektirmektedir.
(FlexCel bileşeni infoplist.exe adlı yardımcı uygulaması aracılığı ile iki xml dosyasını derleme sonrasında çalıştırıp içe alma bu yazı muhteviyatına alınmadı. Uygulamanızı adım adım nasıl kaydedeceğinizi iOS tutorial altında bulabilirsiniz.)
Herşey ayarlandıysa uygulamanız telefonun diğer uygulamaları tarafından “Open in” diyalogunda görüntülenir.
“Open in” olayını cevaplamak
Uygulamanızı xlsx dosyalarını yakalayan bir uyg.olarak kaydettiğinizde, diğer uygulamaların “Open in” dialoglarında görüntülenecektir. Kullanıcı uygulamanızın simgesine tıkladığında da iOS dosyayı <Uygulamanızın dizini>/Documents/Inbox dizini altına kopyalacaktır (Bkz “A look at some of the available folders for your application”).
iOS uygulamanızı başlattıktan ve ona application:OpenUrl: iletisi gönderdiktan sonra, uygulamayı ancak açabilirsiniz. O halde bir şeyler yapmak için, application:OpenUrl: olayını dinlemeniz gerekmektedir.
Delphi’de aşağıdaki komutlar ile bu olayı dinleyebilirsiniz:
Başlatma kodu: (Formunuzun Create olayına ya da projenizin initialization kısmına ekleyiniz)
IFmxApplicationEventService(TPlatformServices.Current.GetPlatformService(IFmxApplicationEventService)).SetApplicationEventHandler(AppHandler);
Olay yakalama:
function TFormFlexView.AppHandler(AAppEvent: TApplicationEvent; AContext: TObject): Boolean; begin Result := true; case AAppEvent of TApplicationEvent.aeOpenURL: begin Result := OpenURL(GetPhysicalPath(AContext as TiOSOpenApplicationContext).URL); end; end; end;
Not: AppHandler fonksiyonu OpenURL üzerinden yakalanan dosyanın tam adı yerine (“file://localhost/folder...” gibi) URL bilgisini gönderir.
Diğer uygulamalardan gelen dosyayı okuma:
OpenURL içinde URL’i bilinen dosya üzerinde okuma işlemi yapabilirsiniz:
iOS’ta dosyanın URL’sini elde ediyoruz, dosya adını değil. Örneğin, alınan URL şöyledir: 'file://localhost/private/var/mobile/Applications/9D16227A-CB01-465D-B8F4-AC43D70C8461/Documents/Inbox/test.xlsx'
Halbuki asıl dosya adı şöyle olmalıdır: ‘/private/var/mobile/Applications/9D16227A-CB01-465D-B8F4-AC43D70C8461/Documents/Inbox/test.xlsx’
iOS metodları normal olarak URL veya yol kullanır. Delphi’nin TFileStream ise yol ile çalışır. Bu yüzden URL’i GetPhysicalPath fonksiyonunu kullanarak yol olarak çevirmeliyiz.
function GetPhysicalPath(const URL: string): string; var FileName: string; FileURL: NSURL; begin FileURL := TNSURL.Wrap(TNSURL.OCClass.URLWithString(NSStr(URL))); Result := UTF8ToString(FileURL.path.UTF8String); end;Not: Delphi 10.4’e kadar, iOS’ta ve Android’de Otomatik Referans Sayıcı /Automated Reference Counting (ARC) sahiptiniz, ki bu da mobil cihazlarda “Free” yi çağırmanıza lüzum yok demekti. Windows’ta ise kodlardaki “… .Free” satırı ve tüm try/except kaldırılarak basitleştirebilir, yine özgün kod çalışır.
Delphi 10.4 ve üstünde mobil platformlar ARC’ye sahip değil, demek ki artık “Free”yi çağırmak zorundasınız. Win32 için tüm nesneleri “free” yapmalısınız.
Dosyaları yedekleme:
Dosyaları kullanmak hakkında bir not: Dosyaların tümünü yedekleme gerekmemektedir ve uygulamanızın statik dosyaları yedeklemesini (yedekleme süresini ve boyutunu artırdığı için) App Store red sebebi olarak kabul etmektedir.
xls veya xlsx dosyalarını uygulamanız için şablon oarak kullanıyorsanız ve bunlar gerçekte lazım olan bilgi olmayıp yedeklemeniz gerekmiyorsa, NSURLIsExcludedFromBackupKey veya kCFURLIsExcludedFromBackupKey özelliklerini kullanıp yedeklemeden ayrı tutmak için kullanmalısınız.
Daha fazla bilgi için bkz: https://developer.apple.com/library/ios/#qa/qa1719/_index.html
Dosya paylaşma için diğer yollar
Dosyaları dışa verme ve içe alma yanında, uygulamanıza dosya alıp vermenin iki yolu daha mevcuttur:
iTunes ile dosya paylaşma
Uygulamanız “iTunes ile paylaş” özelliğini de sunabilir. Açmak için Info.plist dosyasına şu anahtarı ilave edin:
<key>UIFileSharingEnabled</key> <true/>Bununla uygulamanız iTunes’da görüntülünecek ve kullanıcı “Documents” dizininden dosya okuma yazma yapabilecektir. Bu arayüz biraz ilkel olmakta birlikte iyi çalışmaktadır.
Not: Tekrar belirtelim ki bazı dosya tipleri için uygulamayı kaydetme durumunda, Delphi IDE’si doğrudan bunu direk olarak izin vermez. Bir Boolean anahtar eklemelisiniz, fakat Delphi sadece string anahtarlara izin vermekte. O halde yine “Uygulamanızı iOS’a kaydetme” konusunda bahsedildiği gibi farklı bir Info.plist oluşturup birleştirmelisiniz. Önceden içe alma için dosya kaydetme yaptıysanız, aynı dosyayı bu giriş için kullanabilirsiniz.
İkaz: Uygulamanız için iTunes ile dosya paylaşmayı açtıysanız, “Documents” dizinindeki dosyalar kullanıcının gerçekten ihtiyacı duyacakları olduğuna emin olun ve diğerlerini başka bir yere mesela “Library” dizinine koyun. Böyle yapmamak App store reddine sebep olabilir. (Bkz: http://stackoverflow.com/questions/10767517/rejected-by-uifilesharingenabled-key-set-to-true )
Project > Deployment
Uygulamanıza dosya vermenin son yolu, Delphi’deki “Menu->Project->Deployment” seçeneğidir.
Tabii ki sadece uygulama paketiniz ile dosya alabilirsiniz, dosyaları doğrudan “Documents” dizinine koyamazsınız. Zira Documents dizinini App store’a yükleyemezsiniz, sadece uygulama paketi yüklenir.
Uygulamanızı “MyApp” olarak adlandırırsanız dizin yapısı şu şekildedir:
Dosyaları sadece şekildeki yeşil dizinlere koyabilirsiniz. Nitekim uygulamanız da App store tarafından dağıtılmaktadır, uygulamayı indiren kullanıcılar da sadece uygulamanızla birlikte gelenlere ulaşılabilecektir.
Öyleyse dağıtım paketimizdeki dosyaları mavi dizinlere nasıl koyacağız? Sıradan teknik iOS’un onları MyApp.app’ın içindeki bazı dizinlere koyması ve uygulamanız başlarken dosyaları “/Documents” veya “/Library”e kopyalamadır.
Delphi bu kabiliyete sahip olduğundan başlatmada dosyaların kopyalamasından endişe etmenize lüzum yoktur. Proje kaynağınıza baktığınızda (menü > “View source”), kodun şöyle olduğunu görebilirsiniz:
program IOSTest; uses System.StartUpCopy, FMX.Forms, ...Projenizdeki ilk birim “System.StartUpCopy”dır. İmleci o satıra koyup açmak için Ctrl-Enter ‘a basarsanız, bu birimin sadece “Uygulamanız.App/StartUp” dizinini aradığını ve tüm dosyaları ve dizinleri ana dizine (root) kopyaladığını görürsünüz.**
Demek ki, “/Documents”e yerleştirmek isterseniz, onun yerine “StartUp/Documents”e yerleştirmelisiniz. “/Library”e yerleştirmek için de, “StartUp/Library”e yerleştirmelisiniz, v.b. Dosyalar uygulama paketiniz içinde kopyalanacak ve sonra da uygulamanız başlatıldığında ana dizine kopyalanacaktır.
Mühim: Cihazlardaki dosya adları büyük-küçük harf duyarlıdır. Tam olarak “StartUp/Documents”a yerleştirmelisiniz. Mesela “Startup/Documents”a yerleştirirseniz, o dosyalar Uygulamanız.App/Startup/Documents içine yerleştirilecektir, Delphi de uygulamanız başladığında onları /Documents içine kopyalayamayacaktır.
* Kaynak:
TMS Software FlexCel iOS Guide https://doc.tmssoftware.com/flexcel/vcl/...guide.html
iOS Tutorial https://doc.tmssoftware.com/flexcel/vcl/...orial.html
** Çevirenin notu: Yazıdakinin aksine iOS “/StartUp/” altındaki dosyaları da uygulama dizini yani kum havuzu altına koymaktadır.
Yukarıda info.plist dosyasının oluşturulması için (FlexCel bileşenine özel) kullanamayacağımız bir yol anlatılmış olup, yazıdan çıkarılmıştır. Bunun yerine bu işi elle yapmalıyız.
İçe alınacak dosya türü kaydı adımları:
1. İçe alınacak bir dosya uzantısı belirleyiniz. Örneğin: .dnm, .xls, .xlsx, .sheet, .txt, …
2. info.plist.TemplateiOS.xml dosyasını açınız.
3. Mevcut satırlar olan
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <%VersionInfoPListKeys%> <%ExtraInfoPListKeys%> <%StoryboardInfoPListKey%> </dict> </plist>arasına en alttaki </dict> satırı üzerine aşağıdaki satırları ilave ediniz:
<key>CFBundleDocumentTypes</key> <array> <dict> <key>CFBundleTypeName</key> <string>iOSDosyaDepolamaPaylasma dosyasi</string> <key>CFBundleTypeRole</key> <string>Editor</string> <key>LSHandlerRank</key> <string>Owner</string> <key>LSItemContentTypes</key> <array> <string>com.delphican.iOSDosyaDepolamaPaylasma.dnm</string> </array> </dict> </array> <key>UTExportedTypeDeclarations</key> <array> <dict> <key>UTTypeDescription</key> <string>DNM dosyasi</string> <key>UTTypeTagSpecification</key> <dict> <key>public.filename-extension</key> <string>dnm</string> <key>public.mime-type</key> <string>application/vnd.sqlite3</string> </dict> <key>UTTypeConformsTo</key> <array> <string>public.data</string> </array> <key>UTTypeIdentifier</key> <string>com.delphican.iOSDosyaDepolamaPaylasma.dnm</string> </dict> </array>
4. Buradaki bilgileri ihtiyacınıza göre düzenlemesiniz.
CFBundleDocumentTypes: CFBundle yazılım paketi tarafından desteklenen belge tipleridir. https://developer.apple.com/documentatio...umenttypes
CFBundle: Görüntüler, sesler, yerelleştirilmiş dizeler ve yürütülebilir kod dahil olmak üzere birçok türde uygulama kaynağını düzenlemek ve bulmak için paket adı verilen bir dizin hiyerarşisi kullanmanıza olanak tanır. macOS'ta paketler, Mach-O çerçevelerinden işlevleri yüklemek ve yürütmek için CFM uygulamaları tarafından da kullanılabilir. Birden çok dili desteklemek veya uygulamanızı birden çok işletim ortamında yürütmek için paketleri kullanabilirsiniz.
CFM: Code Fragment Manager MacOS bellek yönetim sistemidir. Carbon uygulamalarının Mac'te çalışan uygulamalardan gelen sistem çağrılarını işlemekten sorumludur.
LS Launch Services: Geçerli uygulama işleminizden diğer uygulamalardaki belgeleri başlatır ve açar. https://developer.apple.com/documentatio...h_services
UTExportedTypeDeclarations: Uniform Type Identifiers uygulamanın sahibi olduğu ve uygulama tarafından dışa verilebilen tekdüzen tip tanımlayıcılarıdır. https://developer.apple.com/documentatio...clarations https://developer.apple.com/library/arch...fiers.html
UTI Uniform Type Identifiers çerçevesi: MIME ve dosya türleriyle eşlenen yaygın türlerin bir koleksiyonunu sağlar. Uygulamanızdaki dosya türlerini açıklamak için projenizde bu türleri kullanın. Bu açıklamalar, sistemin aktarım için dosya depolama biçimlerini veya bellek içi verileri düzgün bir şekilde işlemesine yardımcı olur; örneğin, çalışma alanına veya çalışma alanından veri aktarımı. Tanımlayıcı türleri, dizinler, birimler veya paketler gibi diğer kaynakları da tanımlayabilir. https://developer.apple.com/documentatio...clarations
public.mime-type
https://mimetype.io/
CFBundleDocumentTypes
CFBundleTypeName: Dosya tipi hakkında tanımlama (iOSDosyaDepolamaPaylasma dosyasi, Excel document, …)
CFBundleTypeRole: Editor, Viewer, Shell, QLGenerator, None olabilir. Editor ile düzenleme yapılabilir. Viewer ile içe alınan dosya salt okunur olarak geçici olarak alınabilir.
LSHandlerRank: Owner, Default, Alternate, None olabilir. Owner çalışıyor.
LSItemContentTypes: <array><string></string></array> arasında bir ya da daha çok dosya türü tanımlanabilir. (com.delphican.iOSDosyaDepolamaPaylasma.dnm, com.microsoft.excel.xls, com.tms.flexcel.xlsx, org.openxmlformats.spreadsheetml.sheet)
UTExportedTypeDeclarations
UTTypeDescription: (Uzantı) tam dosya türü adı
UTTypeTagSpecification: Array türünde çok sayıda tanımlanabilir. public.filename-extension kullanılır.
public.filename-extension anahtarı altında belirlediğimiz İçe alınacak dosya uzantıları eklenir ( .dnm, .xls, .xlsx, .sheet, .txt, …)
UTTypeConformsTo: Array türünde çok sayıda tanımlanabilir. public.data (, public.database, …)
UTTypeIdentifier: com.şirket.uygulama.uzantı (com.delphican.iOSDosyaDepolamaPaylasma.dnm, com.tms.flexcel.xlsx, …)
5. Projenizin derleme sırasında ve iOSDevice64\Debug veya iOSDevice64\Release altında projeadı. info.plist dosyasını tetkik ediniz.
6. İçe alma işlemini iOS info.plist içindeki dosya türünü kullanarak halledecektir. “.dnm” uzantılı bir dosyayı eposta, Whatsapp, vb. bir uygulama ile cihazınıza gönderip test edebilirsiniz. Open in menüsünde uygulamanız gösterilmezse info.plist içindekiler hatalıdır.
Dosyaları Dışa Verme (Export) ve Paylaşma
Dosyaları diğer uygulamalar için dışa verme yukarıda gördüğümüz dosyaları içe almanın tersidir. Şimdi de kullanıcıya oluşturduğumuz dosyayı açabilecek tüm uygulamaları bir diyalog halinde göstermeliyiz.
iOS’ta dosyaları dışa vermek ve paylaşmak aynı şeydir. Dosya paylaşma arayüzünde kaydırma menüsünde “Kopyala, Yeni Hızlı Not, Dosyalara Kaydet, Etiket Ekle” seçenekleri gösterilmektedir. “Dosyalara Kaydet” seçip “Göz At” arayüzü ile Konumlar (iPhone’umda, iCloud Drive, İndirilenler) dizinlerinde dosya kaydedilebilmektedir. Bu dosyaları sonradan sadece kullanıcının kendisi Dosyalar uygulaması üzerinden ulaşabilmektedir. Bizim uygulamalarımız ise kendi kaydettikleri dosyalara yine ulaşamamaktadır.
Delphi örneklerindeki \Samples\Object Pascal\Mobile Snippets\ShareSheet projesi sadece kamera ile resim çekip paylaşma yeteneğini göstermektedir. Dosya dışa verme ve paylaşma kısmı bulunmamaktadır.
Avustralyalı Delphi Worlds topluluğu tarafından hazırlanan “Kastri“çoklu platform kütüphanesi, RAD Studio Delphi’nin bazı önemli eksik API’lerini tamamlamaktadır. “ShareItems” desteği Delphi’deki ShareSheet aksiyonlarının alternatifidir. Metin, resim ve dosyaların paylaşılmasını sağlamaktadır.
TShareItems üzerinden AddFile, AddImage veya AddText her biri çağırılarak paylaşılacak öğeler eklenebilir.
“Share” metodu ile önceden eklenmiş öğeler dışarıya verilip paylaşılabilir. iOS’un AExcludedActivities parametresini kullanarak paylaşılacak faaliyetleri sınırlayabilirsiniz. Bugün için bunlar:
- Facebook
- Twitter
- Message
- Mail
- Printer
- Pasteboard
- Contacts
- Camera Roll
- Reading List
- Flickr
- Vimeo
- Weibo
- Tencent Weibo
- AirDrop
- IBooks
- PDF
Kaynak: https://github.com/DelphiWorlds/Kastri/t...ShareItems
“ShareItems” desteğini kullanmak için https://github.com/DelphiWorlds/Kastri sitesinden kod zip olarak indirilip,
Project > Options > Building > Delphi Compiler > Search path :
C:\Kastri-master\API;C:\Kastri-master\Core;C:\Kastri-master\Include;C:\Kastri-master\Features;C:\Kastri-master\Features\ShareItems
dizinleri kaydedilmelidir.
Başlatma kodu: (Formunuzun Create olayına ya da projenizin initialization kısmına ekleyiniz)
FShareItems := TShareItems.Create; FShareItems.OnShareCompleted := ShareItemsShareCompletedHandler;Dışa verme Paylaşma:
procedure TForm1.ButtonDahilidenHariciyeKopyalaPaylasMetinClick (Sender: TObject); begin FShareItems.AddFile(TPath.Combine(yol, 'Metin.txt')); FShareItems.Share(ButtonDahilidenHariciyeKopyalaPaylasMetin, FExcluded); end;Sonucu Yakalama:
procedure TForm1.ShareItemsShareCompletedHandler(Sender: TObject;
const AActivity: TShareActivity; const AError: string);
begin
if AActivity = TShareActivity.None then
ShowMessage('Paylaşma iptal edildi')
else
ShowMessage('Paylaşma tamamlandı');
end;
Apple Dosya Sistemi Programlama Rehberi https://developer.apple.com/library/arch...72-CH2-SW4
iOS’ta Dizinler - Delphi Fonksiyon Karşılıkları
GetHomePath: /private/var/mobile/Containers/Data/Application/D232D883-5618-42FB-AC55-84A26D4FEF10
GetDocumentsPath: /var/mobile/Containers/Data/Application/D232D883-5618-42FB-AC55-84A26D4FEF10/Documents
GetCachePath: /var/mobile/Containers/Data/Application/D232D883-5618-42FB-AC55-84A26D4FEF10/Library/Caches
GetLibraryPath: /var/mobile/Containers/Data/Application/D232D883-5618-42FB-AC55-84A26D4FEF10/Library
GetTempPath: /private/var/mobile/Containers/Data/Application/D232D883-5618-42FB-AC55-84A26D4FEF10/tmp
GetPublicPath:
GetPicturesPath:
GetCameraPath:
GetMusicPath:
GetMoviesPath:
GetAlarmsPath:
GetRingtonesPath:
GetDownloadsPath:
GetSharedDocumentsPath:
GetSharedDownloadsPath:
GetSharedCameraPath:
GetSharedAlarmsPath:
GetSharedPicturesPath:
GetSharedMusicPath:
GetSharedMoviesPath:
GetSharedRingTonesPath:
(Project > Deployment > Remote Path : \StartUp\Documents\ = GetDocumentsPath)
· Görüldüğü gibi sadece GetHomePath, GetDocumentsPath, GetCachePath, GetLibraryPath, GetTempPath dahili depolama dizinleri olup, bunlardaki dosyaları okuyabilmekteyiz. Diğer harici dizinler ise kum havuzu dışında olduğundan, ulaşılamayıp boş karşılık vermektedir. Sonuç olarak iOS’ta sadece Dahili Depolamaya sahibiz. Harici Depolamaya ulaşamıyoruz.
· Delphi 11.2 Architect Trial, MacOS 12 Monterey, iOS 16.1.1 kullanılmıştır. Bu arada AMD işlemcili bilgisayarlarda VirtualBox ile iOS uygulama yazmakta sıkıntı yok ama ayarlar uğraştırıyor. iPhone cihazı VirtualBox MacOS’un görmesi için Finder’ı açın. Usb kablosu ile bağlayıp Ayarlar > Hücresel > Hücresel Veri kapalı ise açın, Kişisel Erişim Noktası açın. İkaz sesi gelene kadar biraz bekleyin. Kişisel Erişim Noktasını kapatıp, yarım dakika kadar bekleyip cihazın Finder’da görüldüğünü tetkik edin. Daha sonra PAServer da açıksa ile Delphi iOS Device 64-bit yanında cihazınızı görebiliyorsunuz.
· “iOSDosyaDepolamaPaylasma” örnek projesinde dahili depolamaya kayıt, metin pdf resim Dışa verme paylaşma ve İçe dosya alma yakalama kodları bulunmaktadır. Hepimize faydalı olması dileği ile.

